﻿using demo.流程图控件;
using EventMgrLib;
using Newtonsoft.Json;
using ScriptClass;
using Sunny.UI;
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Design;
using System.Drawing.Drawing2D;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace demo
{
    /// <summary>
    /// 自定义控件 GroupBox文字居中
    /// </summary>
    public class Frame : GroupBox
    {
        private string _text = "";

        /// <summary>
        /// 构造函数
        /// </summary>
        public Frame()
        {
            base.Text = "";
        }

        [Browsable(true)]
        [Category("Appearance")]
        [DefaultValue("GroupBoxText")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)]
        public new string Text
        {
            get
            {

                return _text;
            }
            set
            {

                _text = value;
                this.Invalidate();
            }
        }

        /// <summary>
        /// 重绘
        /// </summary>
        /// <param name="e"></param>
        protected override void OnPaint(PaintEventArgs e)
        {
            //first let the base class to draw the control 
            base.OnPaint(e);
            //create a brush with fore color
            SolidBrush colorBrush = new SolidBrush(this.ForeColor);
            //create a brush with back color
            var backColor = new SolidBrush(this.BackColor);
            //measure the text size
            var size = TextRenderer.MeasureText(this.Text, this.Font);
            // evaluate the postiong of text from left;
            int left = (this.Width - size.Width) / 2;
            //draw a fill rectangle in order to remove the border
            e.Graphics.FillRectangle(backColor, new Rectangle(left, 0, size.Width, size.Height));
            //draw the text Now
            e.Graphics.DrawString(this.Text, this.Font, colorBrush, new PointF(left, 0));
        }
    }
    /// <summary>
    /// //自定义属性下拉效果的类，该类主要继承StringConverter类，并重载该类的一些虚拟方法
    /// </summary>
    public class typeItem : StringConverter
    {
        /// <summary>
        /// true启用，false禁用
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
        {
            return true;
        }

        public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
        {
            return new StandardValuesCollection(new List<string>
            {
                typeof(bool).FullName,
                typeof(short).FullName,
                typeof(ushort).FullName,
                typeof(int).FullName,
                typeof(uint).FullName,
                typeof(long).FullName,
                typeof(ulong).FullName,
                typeof(string).FullName,
                typeof(double).FullName,
                typeof(float).FullName,
                typeof(object).FullName,
            }); //编辑下拉框中的items
        }

        /// <summary>
        /// true：禁用文本编辑。false：启用文本编辑；
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
        {
            return true;
        }
    }

    /// <summary>
    ///propertygrid 脚本的自定义属性弹窗输入功能 必须继承该类，因为所有的propertygrid都是直接或间接继承自该类
    /// </summary>
    public class propertyScriptEdit : UITypeEditor
    {
        /// <summary>
        /// 指定为模式窗体属性编辑器类型
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {

            return UITypeEditorEditStyle.DropDown;//Modal为省略号类型，DropDown为下拉列表
        }

        /// <summary>
        /// 打开属性编辑器修改数据 可指定文件路径 可弹窗 只要实现该方法
        /// </summary>
        /// <param name="context"></param>
        /// <param name="provider"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {

            return FrmScript.EditValue(value);//editScript就是前面新建的窗体，获得窗体中的值
        }
    }

    /// <summary>
    /// propertygrid控件 隐藏属性 使用：1.实例化 2.属性控件选择该对象
    /// </summary>
    public class CustomProperty : ICustomTypeDescriptor
    {
        /// <summary>
        /// 当前选择对象
        /// </summary>
        private object mCurrentSelectObject;

        /// <summary>
        /// 对象属性字典
        /// </summary>
        private Dictionary<string, string> mObjectAttribs = new Dictionary<string, string>();


        public CustomProperty(object pSelectObject)
        {
            mCurrentSelectObject = pSelectObject;            
            mObjectAttribs.Add("Code", "背影色");//想要不显示哪个属性就添加进去
        }

        #region ICustomTypeDescriptor接口成员

        public AttributeCollection GetAttributes()
        {
            return TypeDescriptor.GetAttributes(mCurrentSelectObject);
        }
        public string GetClassName()
        {
            return TypeDescriptor.GetClassName(mCurrentSelectObject);
        }
        public string GetComponentName()
        {
            return TypeDescriptor.GetComponentName(mCurrentSelectObject);
        }
        public TypeConverter GetConverter()
        {
            return TypeDescriptor.GetConverter(mCurrentSelectObject);
        }
        public EventDescriptor GetDefaultEvent()
        {
            return TypeDescriptor.GetDefaultEvent(mCurrentSelectObject);
        }
        public PropertyDescriptor GetDefaultProperty()
        {
            return TypeDescriptor.GetDefaultProperty(mCurrentSelectObject);
        }
        public object GetEditor(Type editorBaseType)
        {
            return TypeDescriptor.GetEditor(mCurrentSelectObject, editorBaseType);
        }
        public EventDescriptorCollection GetEvents(Attribute[] attributes)
        {
            return TypeDescriptor.GetEvents(mCurrentSelectObject, attributes);
        }
        public EventDescriptorCollection GetEvents()
        {
            return TypeDescriptor.GetEvents(mCurrentSelectObject);
        }
        public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            List<CustomPropertyDescriptor> tmpPDCLst = new List<CustomPropertyDescriptor>();
            PropertyDescriptorCollection tmpPDC = TypeDescriptor.GetProperties(mCurrentSelectObject, attributes);
            IEnumerator tmpIe = tmpPDC.GetEnumerator();
            CustomPropertyDescriptor tmpCPD;
            PropertyDescriptor tmpPD;
            while (tmpIe.MoveNext())
            {
                tmpPD = tmpIe.Current as PropertyDescriptor;
                if (mObjectAttribs.ContainsKey(tmpPD.Name))
                {
                    //tmpCPD = new CustomPropertyDescriptor(mCurrentSelectObject, tmpPD);
                    //tmpCPD.SetDisplayName(mObjectAttribs[tmpPD.Name]);
                    //tmpCPD.SetCategory(tmpPD.Category);
                    //tmpPDCLst.Add(tmpCPD);
                }
                else
                {
                    tmpCPD = new CustomPropertyDescriptor(mCurrentSelectObject, tmpPD);
                    //tmpCPD.SetDisplayName(mObjectAttribs[tmpPD.Name]);
                    //tmpCPD.SetCategory(tmpPD.Category);
                    tmpPDCLst.Add(tmpCPD);
                }
            }
            return new PropertyDescriptorCollection(tmpPDCLst.ToArray());
        }
        public PropertyDescriptorCollection GetProperties()
        {
            return TypeDescriptor.GetProperties(mCurrentSelectObject);
        }
        public object GetPropertyOwner(PropertyDescriptor pd)
        {
            return mCurrentSelectObject;
        }
        #endregion
        class CustomPropertyDescriptor : PropertyDescriptor
        {
            private PropertyDescriptor mProp;
            private object mComponent;

            public CustomPropertyDescriptor(object pComponent, PropertyDescriptor pPD)
              : base(pPD)
            {
                mCategory = base.Category;
                mDisplayName = base.DisplayName;
                mProp = pPD;
                mComponent = pComponent;
            }
            private string mCategory;
            public override string Category
            {
                get { return mCategory; }
            }
            private string mDisplayName;
            public override string DisplayName
            {
                get { return mDisplayName; }
            }
            public void SetDisplayName(string pDispalyName)
            {
                mDisplayName = pDispalyName;
            }
            public void SetCategory(string pCategory)
            {
                mCategory = pCategory;
            }
            public override bool CanResetValue(object component)
            {
                return mProp.CanResetValue(component);
            }

            public override Type ComponentType
            {
                get { return mProp.ComponentType; }
            }

            public override object GetValue(object component)
            {
                return mProp.GetValue(component);
            }

            public override bool IsReadOnly
            {
                get { return mProp.IsReadOnly; }
            }

            public override Type PropertyType
            {
                get { return mProp.PropertyType; }
            }
            public override void ResetValue(object component) { mProp.ResetValue(component); }
            public override void SetValue(object component, object value) { mProp.SetValue(component, value); }
            public override bool ShouldSerializeValue(object component)
            {
                return mProp.ShouldSerializeValue(component);
            }
        }
    }

    /// <summary>
    /// propertygrid控件 只显示想要的属性 使用：propertyGrid1.SelectedObject = new CustomObjectWrapper(对象);
    /// </summary>
    public class CustomObjectWrapper : CustomTypeDescriptor
    {
        public object WrappedObject { get; private set; }
        public List<string> BrowsableProperties { get; private set; }
        public CustomObjectWrapper(object o)
            : base(TypeDescriptor.GetProvider(o).GetTypeDescriptor(o))
        {
            WrappedObject = o;
            BrowsableProperties = new List<string>() { "BoolExpression"};
        }
        public override PropertyDescriptorCollection GetProperties()
        {
            return this.GetProperties(new Attribute[] { });
        }
        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
                                 .Where(p => BrowsableProperties.Contains(p.Name))
                                 .Select(p => TypeDescriptor.CreateProperty(
                                     WrappedObject.GetType(),
                                     p,
                                     p.Attributes.Cast<Attribute>().ToArray()))
                                 .ToArray();
            return new PropertyDescriptorCollection(properties);
        }
    }

    #region  用于只显示脚本内容
    public class ScriptObjectWrapper : CustomTypeDescriptor
    {
        public object WrappedObject { get; private set; }
        public List<string> BrowsableProperties { get; private set; }
        public ScriptObjectWrapper(object o)
            : base(TypeDescriptor.GetProvider(o).GetTypeDescriptor(o))
        {
            WrappedObject = o;
            BrowsableProperties = new List<string>() { "Code" };
        }
        public override PropertyDescriptorCollection GetProperties()
        {
            return this.GetProperties(new Attribute[] { });
        }
        public override PropertyDescriptorCollection GetProperties(Attribute[] attributes)
        {
            var properties = base.GetProperties(attributes).Cast<PropertyDescriptor>()
                                 .Where(p => BrowsableProperties.Contains(p.Name))
                                 .Select(p => TypeDescriptor.CreateProperty(
                                     WrappedObject.GetType(),
                                     p,
                                     p.Attributes.Cast<Attribute>().ToArray()))
                                 .ToArray();
            return new PropertyDescriptorCollection(properties);
        }
    }
    #endregion

    /// <summary>
    /// 自定义属性弹窗输入功能 必须继承该类，因为所有的propertygrid都是直接或间接继承自该类
    /// </summary>
    public class propertyEdit : UITypeEditor
    {
        /// <summary>
        /// 指定为模式窗体属性编辑器类型
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public override UITypeEditorEditStyle GetEditStyle(System.ComponentModel.ITypeDescriptorContext context)
        {
            
            return UITypeEditorEditStyle.DropDown;//Modal为省略号类型，DropDown为下拉列表
        }

        /// <summary>
        /// 打开属性编辑器修改数据
        /// </summary>
        /// <param name="context"></param>
        /// <param name="provider"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
        {
            
            return EditScript.EditValue(value);//editScript就是前面新建的窗体，获得窗体中的值
        }
    }

    /// <summary>
    /// 继承集合list用于添加和移除集合元素时自定义事件
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class MyList<T> : List<T> 
    {
        public event Action<T> ItemAdded;

        public new void Add(T obj)
        {
            base.Add(obj);
            ItemAdded?.Invoke(obj);
        }

        public event Action<T> ItemRemove;

        public new void Remove(T obj)
        {
            base.Remove(obj);
            ItemRemove?.Invoke(obj);
        }
    }

    /// <summary>
    /// 特性类，想要反射的类和方法需要加上[ReflectAble]特性，才能根据特性才能反射出方法
    /// </summary>
    public class ReflectAble : Attribute
    {
        /// <summary>
        /// 获取可用的类型，一个DLL里可能有很多类，类只添加了ReflectAble特性才能被反射
        /// </summary>
        /// <param name="dll"></param>
        /// <returns></returns>
        public static List<Type> GetTypes(string dll)
        {
            try
            {
                Assembly curDll = Assembly.LoadFile(dll);
                var types = curDll.GetTypes();
                List<Type> AvailableType = new List<Type>();
                foreach (var type in types)
                {
                    //获得方法的特性
                    var attrList = type.GetCustomAttributes();
                    //枚举特性
                    foreach (var attr in attrList)
                    {
                        if (attr.GetType() == typeof(ReflectAble))//检查特性类型
                        {
                            AvailableType.Add(type);
                        }
                    }
                }
                return AvailableType;
            }
            catch (Exception)
            {

                return null;
            }

        }
        /// <summary>
        ///  获取可用的方法，一个类里所有方法
        /// </summary>
        /// <param name="objType"></param>
        /// <returns></returns>
        public static List<MethodInfo> GetMethods(Type objType)
        {
            try
            {
                List<MethodInfo> AvailableMethods = new List<MethodInfo>();
                var methods = objType.GetMethods();
                foreach (var mds in methods)
                {
                    AvailableMethods.Add(mds);
                }
                return AvailableMethods;
            }
            catch (Exception)
            {

                return null;
            }

        }
        /// <summary>
        /// 获取添加了ReflectAble特性的方法
        /// </summary>
        /// <param name="objType"></param>
        /// <returns></returns>
        public static List<MethodInfo> GetMethod(Type objType)
        {
            try
            {
                List<MethodInfo> AvailableMethods = new List<MethodInfo>();
                MethodInfo[] methods = objType.GetMethods();//获得类中的所有方法
                foreach (MethodInfo mds in methods)
                {
                    try
                    {
                        if (mds.IsDefined(typeof(ReflectAble), true))//检查特性类型
                        {
                            AvailableMethods.Add(mds);
                        }
                    }
                    catch (Exception)
                    {


                    }

                }
                return AvailableMethods;
            }
            catch (Exception)
            {

                return null;
            }

        }
    }
    /// <summary>
    /// 反射方法类,获取方法的信息，在创建工具时使用
    /// </summary>
    public class Reflections 
    {
        /// <summary>
        /// 通过路径，获得Dll类型存到集合里
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public List<Type> DllGetType(string fileName)
        {
            return ReflectAble.GetTypes(fileName);
        }
        /// <summary>
        /// 通过类型，获得类里的方法存到集合里
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public List<MethodInfo> DllGetMethods(Type type)
        {
            return ReflectAble.GetMethods(type);
        }
        /// <summary>
        /// 通过类型，获得类里具有特性的方法存到集合里
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public List<MethodInfo> DllGetReflectAbleMethod(Type type)
        {
            return ReflectAble.GetMethod(type);
        }
        /// <summary>
        /// 通过方法属性确认是否静态方法
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        public bool DllIsStatic(MethodInfo methodInfo)
        {
            return methodInfo.IsStatic;
        }
        /// <summary>
        /// 通过类型属性确认类型名称，类型就是类名
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public string DllGetTypeName(Type type)
        {
            return type.FullName;
        }
        /// <summary>
        /// 通过方法属性确认方法返回类型
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <returns></returns>
        public string DllGetReturnType(MethodInfo methodInfo)
        {
            return methodInfo.ReturnType.FullName;
        }
        /// <summary>
        /// 通过方法获取方法参数类型和名称
        /// </summary>
        /// <param name="methodInfo"></param>
        /// <param name="ParaTypes"></param>
        /// <param name="ParaNames"></param>
        public void DllGetParam(MethodInfo methodInfo,ref List<string> ParaTypes, ref List<string> ParaNames)
        {
            ParameterInfo[] methodParameter = (methodInfo)?.GetParameters();
            ParaTypes.Clear();
            ParaNames.Clear();
            if (methodParameter != null)
            {
                foreach (var parameter in methodParameter)
                {
                    ParaTypes.Add(parameter.ParameterType.FullName);
                    ParaNames.Add(parameter.Name);
                }

            }
        }
    }
    /// <summary>
    /// 全局变量类，用于记录全局变量信息
    /// </summary>
    public class VarInfo : BindableBase
    { 
        
        private string _name;
        /// <summary>
        /// 全局变量变量名称
        /// </summary>
        [Description("全局变量变量名称")]
        public string Name
        {
            get { return _name; }
            set { SetProperty(ref _name, value); }
        }
        //全局变量唯一标识
        [Description("全局变量变量名称"),ReadOnly(true)]
        public string VarId { get; set; } = Guid.NewGuid().ToString();
        
        private string _group;
        /// <summary>
        /// 全局变量变量分组
        /// </summary>
        [Description("全局变量变量分组")]
        public string Group
        {
            get { return _group; }
            set { SetProperty(ref _group, value); }
        }
        
              
        private string _type;
        /// <summary>
        /// 全局变量变量类型 
        /// </summary>
        [Description("全局变量变量类型"), TypeConverter(typeof(typeItem))]
        public string Type
        {
            get { return _type; }
            set 
            {
                
                SetProperty(ref _type, value);
                InitValue = Type;
            }
        }
 
        
        private object _initValue;
        /// <summary>
        ///  全局变量初始值
        /// </summary>
        [Description("全局变量初始值"), Editor(typeof(propertyEdit), typeof(UITypeEditor))]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public object InitValue
        {
            get { return _initValue; }
            set 
            {

                SetProperty(ref _initValue, value);
            }
        }
        
        
        private object _value;
        /// <summary>
        /// 全局变量当前值
        /// </summary>
        [Description("全局变量当前值")]
        [TypeConverter(typeof(ExpandableObjectConverter))]
        [EditorBrowsable(EditorBrowsableState.Always)]
        public object Value
        {
            get { return _value; }
            set { SetProperty(ref _value, value); }
        }       

        private int _editPermission;
        /// <summary>
        /// 全局变量可以编辑的权限,用int可以比较权限大小
        /// </summary>
        [Description("全局变量可以编辑的权限,用int可以比较权限大小")]
        public int EditPermission
        {
            get { return _editPermission; }
            set { SetProperty(ref _editPermission, value); }
        }
        
        
        private dynamic _min;
        /// <summary>
        /// 全局变量最小值
        /// </summary>
        [Description("全局变量最小值")]
        public dynamic Min
        {
            get { return _min; }
            set { SetProperty(ref _min, value); }
        }
        
      
        private dynamic _max;
        /// <summary>
        /// 全局变量最大值
        /// </summary>
        [Description("全局变量最大值")]
        public dynamic Max
        {
            get { return _max; }
            set { SetProperty(ref _max, value); }
        }
        
       
        private string _remark;
        /// <summary>
        /// 全局变量备注
        /// </summary>
        [Description("全局变量备注")]
        public string Remark
        {
            get { return _remark; }
            set { SetProperty(ref _remark, value); }
        }
        
    }
    /// <summary>
    /// 存储全局变量类
    /// </summary>
    public class GlobalVars
    {
        #region 单例

        private static readonly Lazy<GlobalVars> Instance = new Lazy<GlobalVars>(() => new GlobalVars());

        public static GlobalVars Ins { get; } = Instance.Value;

        private GlobalVars()
        {
            Vars = new ConcurrentDictionary<string, ConcurrentDictionary<string, VarInfo>>();
        }

        #endregion 单例

        #region 属性

        /// <summary>
        /// 根据键确认各个分支存储的全局变量
        /// </summary>
        public ConcurrentDictionary<string, ConcurrentDictionary<string, VarInfo>> Vars { get; }

        #endregion 属性

        #region 存储键的分支分组常量

        public static readonly string FlowVars = "FlowVars";
        public static readonly string MotionMgr = "MotionMgr";
        //public static readonly string IOCards = "IOCards";
        //public static readonly string IOConfig = "IOConfig";
        public static readonly string IOMgr = "IOMgr";
        public static readonly string StationsMgr = "StationsMgr";
        //public static readonly string DI = "DI";
        //public static readonly string DO = "DO";
        public static readonly string Points = "Points";
        public static readonly string ProductPars = "ProductPars";
        public static readonly string SystemPars = "SystemPars";
        //视觉相关
        //报表相关

        #endregion 分组常量

        #region 公共方法

        /// <summary>
        /// 加载字典
        /// </summary>
        /// <param name="dicName"></param>
        /// <param name="filePath"></param>
        /// <param name="iniValue"></param>
        public void LoadDic(string dicName, string filePath, bool iniValue = true)
        {
            var vars = Json.LoadExt<Dictionary<string, VarInfo>>(filePath);//临时字典用于反序列化
            var dicVars = new ConcurrentDictionary<string, VarInfo>();

            try
            {
                if (vars == null) return;
                ConvertInt(vars, iniValue);
                DicToConcurrentDic(vars, dicVars);
            }
            catch (Exception e)
            {
                UIMessageBox.ShowError($"加载变量集{dicName}时发生了异常\r{e.Message}");
            }
            finally
            {
                if (Ins.Vars.ContainsKey(dicName))
                {
                    Ins.Vars[dicName] = dicVars;
                }
                else
                {
                    Ins.Vars.TryAdd(dicName, dicVars);
                }
            }
        }
        /// <summary>
        /// 保存字典
        /// </summary>
        /// <param name="dicName"></param>
        /// <param name="filePath"></param>
        public void SaveDic(string dicName, string filePath)
        {
            if (Ins.Vars.ContainsKey(dicName))
            {
                var vars = new Dictionary<string, VarInfo>();
                ConcurrentDicToDic(Ins.Vars[dicName], vars);
                Json.SaveExt<Dictionary<string, VarInfo>>(filePath, vars);
            }
        }
        /// <summary>
        /// UIComboTreeView控件加载全局变量数据
        /// </summary>
        /// <param name="tv"></param>
        /// <param name="varType"></param>
        public void ComboTreeLoadData(UIComboTreeView tv, string varType)
        {
            tv.Nodes.Clear();
            foreach (var dic in Vars.Keys)
            {   
                //分支键
                var dicNode = new TreeNode(dic);
                //根据分支键的全局变量值的分组，得到分组
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();

                foreach (var @group in groups)
                {
                    //创建分组树节点
                    var groupNode = new TreeNode(@group);
                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (varInfo.Group == @group)
                        {
                            if (varInfo.Type == varType)
                            {
                                var node = groupNode.Nodes.Add(varInfo.Name);
                                node.Tag = varInfo.VarId;
                            }
                        }
                    }
                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);
                    }
                }
                if (dicNode.Nodes.Count > 0)
                {
                    tv.Nodes.Add(dicNode);
                }
            }
        }

        /// <summary>
        /// UIComboTreeView控件加载全局变量数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="tv"></param>
        public void ComboTreeLoadData<T>(UIComboTreeView tv)
        {
            tv.Nodes.Clear();
            foreach (string dic in Vars.Keys)
            {
                TreeNode dicNode = new TreeNode(dic);
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();
                foreach (var group in groups)
                {
                    TreeNode groupNode = new TreeNode(@group);

                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (!Vars[dic].ContainsKey(varInfo.Name)) continue;
                        if (Vars[dic][varInfo.Name].Group == @group)
                        {
                            if (!string.IsNullOrEmpty(varInfo.Type))
                            {
                                if (varInfo.Value is T)
                                {
                                    var node = groupNode.Nodes.Add(varInfo.Name);
                                    node.Tag = varInfo.VarId;
                                }
                            }
                        }
                    }

                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);
                    }
                }

                if (dicNode.Nodes.Count > 0)
                {
                    tv.Nodes.Add(dicNode);
                }
            }
        }

        /// <summary>
        /// UIComboTreeView控件加载全局变量数据
        /// </summary>
        /// <param name="tv"></param>
        /// <param name="varType"></param>
        public void ComboTreeLoadData(UIComboTreeView tv, List<string> varType)
        {
            tv.Nodes.Clear();
            foreach (string dic in Vars.Keys)
            {
                TreeNode dicNode = new TreeNode(dic);
                var groups = Vars[dic].Values.Select(varInfo => varInfo.Group).ToList().Distinct().ToList();
                foreach (var group in groups)
                {
                    TreeNode groupNode = new TreeNode(@group);

                    foreach (var varInfo in Vars[dic].Values)
                    {
                        if (!Vars[dic].ContainsKey(varInfo.Name)) break;
                        if (Vars[dic][varInfo.Name].Group == @group)
                        {
                            if (!string.IsNullOrEmpty(varInfo.Type))
                            {
                                if (varType.Contains(varInfo.Type))
                                {
                                    var node = groupNode.Nodes.Add(varInfo.Name);
                                    node.Tag = varInfo.VarId;
                                }
                            }
                        }
                    }

                    if (groupNode.Nodes.Count > 0)
                    {
                        dicNode.Nodes.Add(groupNode);
                    }
                }

                if (dicNode.Nodes.Count > 0)
                {
                    tv.Nodes.Add(dicNode);
                }
            }
        }

        /// <summary>
        /// 根据全局变量ID获得全局变量
        /// </summary>
        /// <param name="varID"></param>
        /// <returns></returns>
        public VarInfo GetVar(string varID)
        {
            //var varInfl = new VarInfo();
            //foreach (var dic in Vars)
            //{
            //    foreach (var varInfo in dic.Value)
            //    {
            //        if (varInfo.Value.VarId == varID)
            //        {
            //            varInfl = dic.Value[varInfo.Key];
            //        }
            //    }
            //}
            
            return (from dic in Vars //from相当于foreach
                    from varInfo in dic.Value //from相当于foreach
                    where varInfo.Value.VarId == varID           //where相当于if
                    select varInfo.Value).FirstOrDefault();  //select相当于return
        }
        /// <summary>
        /// 获取所有已使用的类型
        /// </summary>
        /// <returns></returns>
        public List<string> GetAllTypes()
        {
            var typeList = new List<string>();
            foreach (var dicVar in Vars)
            {
                foreach (var varInfo in dicVar.Value)
                {
                    if (!typeList.Contains(varInfo.Value.Type))
                    {
                        typeList.Add(varInfo.Value.Type);
                    }
                }
            }
            return typeList;
        }
        /// <summary>
        /// 获取存储参数路径
        /// </summary>
        /// <param name="folder"></param>
        /// <returns></returns>
        public string GetConfigPath(string folder = "")
        {

            string allConfigPath = Environment.CurrentDirectory + "\\Config\\";
            if (!Directory.Exists(allConfigPath))
            {
                Directory.CreateDirectory(allConfigPath);
            }
            string cfgPath = allConfigPath;
            if (!string.IsNullOrEmpty(folder))
            {
                cfgPath += "\\" + folder;
            }

            if (!Directory.Exists(cfgPath))
            {
                Directory.CreateDirectory(cfgPath);
            }
            return cfgPath;
        }

        #endregion 公共方法

        #region 私有方法

        /// <summary>
        /// 普通字典转换并发字典
        /// </summary>
        /// <param name="dic"></param>
        /// <param name="conDic"></param>
        private static void DicToConcurrentDic(Dictionary<string, VarInfo> dic,
            ConcurrentDictionary<string, VarInfo> conDic)
        {
            conDic.Clear();
            foreach (var varInfo in dic)
            {
                conDic.TryAdd(varInfo.Key, varInfo.Value);
            }
        }

        /// <summary>
        /// 并发字典转普通字典
        /// </summary>
        /// <param name="conDic"></param>
        /// <param name="dic"></param>
        private static void ConcurrentDicToDic(ConcurrentDictionary<string, VarInfo> conDic,
            Dictionary<string, VarInfo> dic)
        {
            dic.Clear();
            foreach (var varInfo in conDic)
            {
                dic.Add(varInfo.Key, varInfo.Value);
            }
        }

        /// <summary>
        /// 解决动态类型int会全部转换为int64的问题
        /// </summary>
        /// <param name="var"></param>
        /// <param name="iniValue"></param>
        private static void ConvertInt(Dictionary<string, VarInfo> var, bool iniValue = true)
        {
            foreach (var par in var.Values)
            {
                Type type = Type.GetType(par.Type);
                ConvertToInt(type, par, iniValue);
                if (iniValue)
                {
                    par.Value = par.InitValue;
                }
            }
        }

        private static void ConvertToInt(Type type, VarInfo par, bool iniValue = true)
        {
            if (type == typeof(int))
            {
                par.Value = Convert.ToInt32(iniValue ? par.InitValue : par.Value);
            }

            if (type == typeof(int))
            {
                par.InitValue = Convert.ToInt32(iniValue ? par.InitValue : par.Value);
            }
            else if (type == typeof(uint))
            {
                par.InitValue = Convert.ToUInt32(iniValue ? par.InitValue : par.Value);
            }
            else if (type == typeof(short))
            {
                par.InitValue = Convert.ToInt16(iniValue ? par.InitValue : par.Value);
            }
            else if (type == typeof(ushort))
            {
                par.InitValue = Convert.ToUInt16(iniValue ? par.InitValue : par.Value);
            }
            else if (type == typeof(int[]))
            {
                par.InitValue = (int[])(iniValue ? par.InitValue : par.Value);
            }
            else if (type == typeof(uint[]))
            {
                par.InitValue = (int[])(iniValue ? par.InitValue : par.Value);
            }
            else if (type == typeof(short[]))
            {
                par.InitValue = (int[])(iniValue ? par.InitValue : par.Value);
            }
            else if (type == typeof(ushort[]))
            {
                par.InitValue = (int[])(iniValue ? par.InitValue : par.Value);
            }
        }

        #endregion 私有方法
    }
    #region 以下为流程图控件相关类
    /// <summary>
    /// 流程类
    /// </summary>
    public class Flow 
    {
        #region 构造

        public Flow()
        {
            ActionItems = new List<ActionItem>();
            Connections = new List<Connection>();
        }

        #endregion 构造

        #region 流程图显示属性，用于赋值给流程图控件

        /// <summary>
        /// 原点视图
        /// </summary>
        public Point ViewOriginPoint { get; set; }
        /// <summary>
        /// 鼠标悬停到线后线的颜色RGB值
        /// </summary>
        public int LineHoveredColorARGB
        {
            get
            {
                return LineHoveredColor.ToArgb();
            }
            set
            {
                LineHoveredColor = Color.FromArgb(value);
            }
        }
        /// <summary>
        /// 鼠标悬停到线后线的颜色
        /// </summary>
        [JsonIgnore]
        public Color LineHoveredColor { get; set; } = Color.Blue;
        /// <summary>
        /// 鼠标选择到线后线的颜色RGB值
        /// </summary>
        public int LineSelectedColorARGB
        {
            get
            {
                return LineSelectedColor.ToArgb();
            }
            set
            {
                LineSelectedColor = Color.FromArgb(value);
            }
        }
        /// <summary>
        /// 鼠标选择到线后线的颜色
        /// </summary>
        [JsonIgnore()]
        public Color LineSelectedColor { get; set; } = Color.Green;
        /// <summary>
        /// 线的颜色RGB值
        /// </summary>
        public int LineColorARGB
        {
            get
            {
                return LineColor.ToArgb();
            }
            set
            {
                LineColor = Color.FromArgb(value);
            }
        }
        /// <summary>
        /// 线的颜色
        /// </summary>
        [JsonIgnore()]
        public Color LineColor { get; set; } = Color.Silver;
        /// <summary>
        /// 背景颜色RGB值
        /// </summary>
        public int BackColorARGB
        {
            get
            {
                return BackColor.ToArgb();
            }
            set
            {
                BackColor = Color.FromArgb(value);
            }
        }
        /// <summary>
        /// 背景颜色，赋值给流程图控件
        /// </summary>
        [JsonIgnore()]
        public Color BackColor { get; set; } = SystemColors.Control;
        /// <summary>
        /// 是否显示网格
        /// </summary>
        public bool ShowGrid { get; set; } = false;

        #endregion 流程图显示属性

        #region 数据结构

        /// <summary>
        /// 任务集合，节点集合，动作集合，工具集合
        /// </summary>
        [Browsable(false)]
        public List<ActionItem> ActionItems { get; set; }

        /// <summary>
        /// 边的集合，连接的集合
        /// </summary>
        [Browsable(false)]
        public List<Connection> Connections { get; set; }

        /// <summary>
        /// 入边集合，就是有进入线的，有两条线就记2，一条线记一，有多条记多条
        /// </summary>
        [JsonIgnore]
        private Dictionary<string, List<ActionItem>> IncomingEdges { get; set; }

        /// <summary>
        /// 出边集合
        /// </summary>
        [JsonIgnore]
        private Dictionary<string, List<ActionItem>> OutgoingEdges { get; set; }

        #endregion 数据结构

        #region 其他属性
        /// <summary>
        /// 流程分组
        /// </summary>
        [Description("分组")]
        public string Group { get; set; }
        /// <summary>
        /// 流程是否启用
        /// </summary>
        [Description("是否启用")]
        public bool InUse { get; set; }
        /// <summary>
        /// 流程名称
        /// </summary>
        [Description("流程名称")]
        public string Name { get; set; }
        /// <summary>
        /// 启动流程的事件名称
        /// </summary>
        [Description("启动流程的事件名称")]
        public string EventName { get; set; }

        #endregion 其他属性

        #region 方法

        public void AddNode(ActionItem item)
        {
        }

        public void DelNode(ActionItem item)
        {
        }

        //private void AddEdges(TKey key, IList<TKey> outgoing)
        //{
        //    OutgoingEdges.Add(key, new HashSet<TKey>(outgoing));
        //    foreach (var dest in outgoing)
        //    {
        //        if (!IncomingEdges.TryGetValue(dest, out HashSet<TKey> incoming))
        //            IncomingEdges[dest] = new HashSet<TKey> { key };
        //        else
        //            incoming.Add(key);
        //    }
        //}
        /// <summary>
        /// 先将流程里所有工具集合ID同时赋值到入编和出边字典键中，再根据边集合ID对应的工具分别赋值到字典的值中
        /// </summary>
        public void GenDic()
        {
            IncomingEdges = new Dictionary<string, List<ActionItem>>();
            OutgoingEdges = new Dictionary<string, List<ActionItem>>();
            foreach (var actionItem in ActionItems)
            {
                IncomingEdges.Add(actionItem.ObjectId, new List<ActionItem>());
                OutgoingEdges.Add(actionItem.ObjectId, new List<ActionItem>());
            }

            foreach (var connection in Connections)
            {
                //入边集合是否含有边集合的到达节点ID
                if (IncomingEdges.ContainsKey(connection.ToID))
                {
                    //入边集合到达节点ID键添加出发节点ID所对应的工具值
                    IncomingEdges[connection.ToID].Add(GetActionItem(connection.FromID));
                }
                //出边集合是否含有边集合的出发节点ID
                if (OutgoingEdges.ContainsKey(connection.FromID))
                {
                    //出边集合到达节点ID键添加到达节点ID所对应的工具值
                    OutgoingEdges[connection.ToID].Add(GetActionItem(connection.ToID));
                }
            }
        }
        /// <summary>
        /// 根据工具ID获得工具
        /// </summary>
        /// <param name="actionID"></param>
        /// <returns></returns>
        public ActionItem GetActionItem(string actionID)
        {
            return ActionItems.FirstOrDefault(tool => tool.ObjectId == actionID);
        }
        /// <summary>
        /// 流程运行方法，先遍历入边集合中没有进入线的认为是起始工具，运行完成后，状态改变，重新遍历入边集合找到有线的，执行
        /// </summary>
        /// <returns></returns>
        public bool Run()
        {
            bool result = true;
            GenDic();
            foreach (var actionItem in ActionItems)
            {
                actionItem.State = ActionItem.ActionState.Idle;
            }

            //有入边，入边已已执行过的执行
            while (true)
            {
                List<ActionItem> waitToRun = new List<ActionItem>();//用于存放等待执行的任务
                foreach (var actionItem in ActionItems)
                {
                    if (actionItem.State != ActionItem.ActionState.Idle) continue;
                    //执行条件1，没有入边的直接执行
                    if (IncomingEdges[actionItem.ObjectId].Count == 0)
                    {
                        actionItem.State = ActionItem.ActionState.Ready;
                        waitToRun.Add(actionItem);
                    }
                    else
                    {
                        //有入边
                        List<ActionItem> incomingActionItems = IncomingEdges[actionItem.ObjectId];
                        bool needToRun = false;
                        foreach (var incomingActionItem in incomingActionItems)
                        {
                            if (actionItem.WaitAny)//执行条件2，只要有任意一个入边执行过，就执行
                            {
                                if (incomingActionItem.State == ActionItem.ActionState.Completed)
                                {
                                    needToRun = true;
                                    break;
                                }
                            }
                            else //执行条件3，所有入边都执行过就执行
                            {
                                if (incomingActionItem.State != ActionItem.ActionState.Completed) //入边有一个没运行过或正在运行不能执行
                                {
                                    needToRun = false;
                                    break;
                                }
                                else
                                {
                                    needToRun = true;
                                }
                            }
                        }

                        if (needToRun)
                        {
                            waitToRun.Add(actionItem);
                        }
                    }
                }

                if (waitToRun.Count == 0) //如果没有等待执行的任务
                {
                    bool someTaskIsRunning = false;//以前执行的任务是否正在执行

                    foreach (var actionItem in ActionItems.Where(actionItem => actionItem.State == ActionItem.ActionState.Running))
                    {
                        someTaskIsRunning = true;
                    }

                    if (!someTaskIsRunning)
                    {
                        //结束条件1,如果没有等待执行的任务,也没有任务正在执行，结束流程
                        return result;
                    }
                }
                if (waitToRun.OfType<EndNode>().Any())
                {
                    foreach (var actionItem in waitToRun)
                    {
                        if (actionItem is EndNode)
                        {
                            actionItem.State = ActionItem.ActionState.Running;
                            Task.Factory.StartNew(actionItem.Run);
                            //结束条件2,如果等待还行的集合有EndNode,直接结束流程
                            return result;
                        }
                    }
                }
                else
                {

                    //并行执行任务
                    foreach (var actionItem in waitToRun)
                    {
                        actionItem.State = ActionItem.ActionState.Running;
                        Task.Factory.StartNew(actionItem.Run);
                    }
                }
                Thread.Sleep(2);
            }
        }

        #endregion 方法
    }
    /// <summary>
    /// 流程信息类
    /// </summary>
    public class FlowsMgr
    {
        #region 单例

        private static readonly Lazy<FlowsMgr> Instance = new Lazy<FlowsMgr>(() => new FlowsMgr());

        private FlowsMgr()
        {
            FlowsPath = Environment.CurrentDirectory + "\\Flows\\";
            if (!Directory.Exists(FlowsPath))
            {
                Directory.CreateDirectory(FlowsPath);
            }
            Flows = new List<Flow>();
        }

        public static FlowsMgr Ins { get; } = Instance.Value;

        #endregion 单例

        #region 属性
        /// <summary>
        /// 流程路径
        /// </summary>
        public string FlowsPath { get; set; }
        /// <summary>
        /// 流程
        /// </summary>
        public List<Flow> Flows { get; set; }

        #endregion 属性
        /// <summary>
        /// 加载流程同时加载变量
        /// </summary>
        public void LoadFLows()
        {
            var files = Directory.GetFiles(FlowsPath, "*.flow");
            foreach (var file in files)
            {
                try
                {
                    var flow = Json.LoadExt<Flow>(file);
                    if (flow != null)
                    {
                        Flows.Add(flow);
                    }
                }
                catch (Exception e)
                {
                    UIMessageBox.ShowError($"加载流程时发现有错误的流程{file}\r{e.Message}");
                }
            }

            GlobalVars.Ins.LoadDic(GlobalVars.FlowVars, FlowsPath + "FLowVars.Var");
        }
        /// <summary>
        /// 保存流程同时保存变量
        /// </summary>
        public void SaveFlows()
        {
            foreach (var flow in Flows)
            {
                Json.SaveExt<Flow>(FlowsPath + flow.Name + ".flow", flow);
            }
            GlobalVars.Ins.SaveDic(GlobalVars.FlowVars, FlowsPath + "FLowVars.Var");
        }
    }
    /// <summary>
    /// 连接边类，记录实体连接边状态信息
    /// </summary>
	public class Connection : Entity
	{
        #region Fields

        #endregion

        #region 属性
        /// <summary>
        /// 连接边类，记录实体连接边状态信息，连接边里的连接点
        /// </summary>
        [Browsable(false), JsonIgnore]
		public List<Connector> Connectors { get; set; }

        /// <summary>
        /// 连接边类，记录实体连接边状态信息，出发点，顶点（节点）的四个连接点之一
        /// </summary>
        [Browsable(true), Description("始节点"), Category("Layout"), JsonIgnore]
		public Connector From
		{
			get
			{
				return from;
			}
			private set
			{
				from = value;
				if (site != null)
					from.Site = site;

				from.OwnerEntity = this;
			}
		}
        protected Connector from;
        /// <summary>
        /// 连接边类，记录实体连接边状态信息，出发节点的GUID，通过GUID可以拿到出发节点
        /// </summary>
        public string FromID { get; set; }

        /// <summary>
        /// 连接边类，记录实体连接边状态信息，头部连接点编号
        /// </summary>
        public int FromIndex { get; set; }


        /// <summary>
        /// 连接边类，记录实体连接边状态信息，终点，顶点（节点）的四个连接点之一
        /// </summary>
        [Browsable(true), Description("终节点"), Category("Layout"), JsonIgnore]
		public Connector To
		{
			get
			{
				return to;
			}
			private set
			{
				to = value;
				if (site != null)
					to.Site = site;

				to.OwnerEntity = this;
			}
		}
        protected Connector to;
        /// <summary>
        /// 连接边类，记录实体连接边状态信息，到达节点的GUID，通过GUID可以拿到到达节点
        /// </summary>
        public string ToID { get; set; }

        /// <summary>
        /// 连接边类，记录实体连接边状态信息，尾部连接点编号
        /// </summary>
        public int ToIndex { get; set; }
        /// <summary>
        /// 连接边类，记录实体连接边状态信息，始节点
        /// </summary>
		[Browsable(true), Description("始节点"), Category("Layout")]
		public bool UseBackColor
		{
			get
			{
				return _useBackColor;
			}
			set
			{
				_useBackColor = value;
			}
		}
        private bool _useBackColor = false;
        /// <summary>
        /// 连接边类，记录实体连接边状态信息，默认颜色
        /// </summary>
        [Browsable(true), Description("默认颜色"), Category("Layout")]
		public Color Color
		{
			get
			{
				return color;
			}
			set
			{
				color = value;
				_useBackColor = true;
			}
		}
        protected Color color = Color.Silver;
        /// <summary>
        /// 连接边类，记录实体连接边状态信息，线选中颜色
        /// </summary>
		[Browsable(true), Description("选中颜色"), Category("Layout")]
		public Color LineSelectedColor
		{
			get
			{
				return lineSelectedColor;
			}
			set
			{
				lineSelectedColor = value;
				_useBackColor = true;
			}
		}
        protected Color lineSelectedColor = Color.Green;
        /// <summary>
        /// 连接边类，记录实体连接边状态信息，线悬停颜色
        /// </summary>
        [Browsable(true), Description("悬停颜色"), Category("Layout")]
		public Color LineHoveredColor
		{
			get
			{
				return lineHoveredColor;
			}
			set
			{
				lineHoveredColor = value;
				_useBackColor = true;
			}
		}
        protected Color lineHoveredColor = Color.Blue;
        #endregion

        #region Constructor
        
        public Connection()
		{

		}

        /// <summary>
        /// 构造两个给定点之间的连接
        /// </summary>
        /// <param name="from">连接的起点</param>
        /// <param name="to">连接的终点</param>
        public Connection(DiagramPoint from, DiagramPoint to)
		{
			Connectors = new List<Connector>();

			this.from = new Connector(from.Copy())
			{
				Name = "From",
				OwnerEntity = this
			};
			this.from.LocationChanged += Connector_LocationChanged;
			var connector1 = this.@from;
			Connectors.Add(connector1);

			this.to = new Connector(to.Copy())
			{
				Name = "To",
				OwnerEntity = this
			};
			var connector2 = this.to;
			this.to.LocationChanged += Connector_LocationChanged;
			this.To.AttachedToChanged += To_AttachedToChanged;
			Connectors.Add(connector2);
		}
        /// <summary>
        /// 位置改变事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
		private void Connector_LocationChanged(object sender, LocationEventArgs e)
		{
			InitialPath();
		}
        /// <summary>
        /// 位置改变事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
		private void To_AttachedToChanged(object sender, AttachedToChangedEventArgs e)
		{
			InitialPath();
		}
        /// <summary>
        /// 连接边的路径重绘
        /// </summary>
		public void InitialPath()
		{
			Connector connector1 = this.from, connector2 = this.to;
			int x = 0, y = 0;
			List<Connector> connectors = new List<Connector> { this.@from };

			#region 下对上

			//connector2.ConnectorDirection = ConnectorDirection.Up;
			if (connector1.ConnectorDirection == ConnectorDirection.Down && connector2.ConnectorDirection == ConnectorDirection.Up)
			{
				if (connector1.Point.Y < connector2.Point.Y && connector1.Point.X != connector2.Point.X)
				{
					x = connector1.Point.X;
					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y >= connector2.Point.Y)
				{
					x = connector1.Point.X;
					y = connector1.Point.Y + 10;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = (connector1.Point.X + connector2.Point.X) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y -= 30 + connector1.Point.Y - connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 下对左

			else if (connector1.ConnectorDirection == ConnectorDirection.Down && connector2.ConnectorDirection == ConnectorDirection.Left)
			{
				if (connector1.Point.Y < connector2.Point.Y && connector1.Point.X >= connector2.Point.X)
				{
					x = connector1.Point.X;
					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X - 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y < connector2.Point.Y)
				{
					x = connector1.Point.X;
					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.X != connector2.Point.X)
				{
					x = connector1.Point.X;
					y = connector1.Point.Y + 10;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X - 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 下对右

			else if (connector1.ConnectorDirection == ConnectorDirection.Down && connector2.ConnectorDirection == ConnectorDirection.Right)
			{
				if (connector1.Point.Y < connector2.Point.Y && connector1.Point.X <= connector2.Point.X)
				{
					x = connector1.Point.X;
					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y < connector2.Point.Y)
				{
					x = connector1.Point.X;
					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.X != connector2.Point.X)
				{
					x = connector1.Point.X;
					y = connector1.Point.Y + 10;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 下对下

			else if (connector1.ConnectorDirection == ConnectorDirection.Down && connector2.ConnectorDirection == ConnectorDirection.Down)
			{
				if (connector1.Point.Y < connector2.Point.Y && connector1.Point.X != connector2.Point.X)
				{
					x = connector1.Point.X;
					y = connector2.Point.Y + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y < connector2.Point.Y)
				{
					x = connector1.Point.X;
					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.X != connector2.Point.X)
				{
					x = connector1.Point.X;
					y = connector1.Point.Y + 10;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else
				{
					x = connector1.Point.X;
					y = connector1.Point.Y + 10;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector1.Point.X + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y -= 10 + (connector1.Point.Y - connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 右对上

			else if (connector1.ConnectorDirection == ConnectorDirection.Right && connector2.ConnectorDirection == ConnectorDirection.Up)
			{
				if (connector1.Point.Y < connector2.Point.Y && connector1.Point.X + 10 >= connector2.Point.X)
				{
					x = connector1.Point.X + 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y < connector2.Point.Y)
				{
					x = connector2.Point.X;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else
				{
					x = connector1.Point.X + 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y - 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 右对右

			else if (connector1.ConnectorDirection == ConnectorDirection.Right && connector2.ConnectorDirection == ConnectorDirection.Right)
			{
				x = Math.Max(connector1.Point.X + 10, connector2.Point.X + 20);
				y = connector1.Point.Y;
				connectors.Add(new Connector(new DiagramPoint(x, y)));

				y = connector2.Point.Y;
				connectors.Add(new Connector(new DiagramPoint(x, y)));
			}

			#endregion

			#region 右对下

			else if (connector1.ConnectorDirection == ConnectorDirection.Right && connector2.ConnectorDirection == ConnectorDirection.Down)
			{
				if (connector1.Point.Y < connector2.Point.Y)
				{
					x = connector1.Point.X + 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y == connector2.Point.Y)
				{
					x = connector1.Point.X + 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector1.Point.Y + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.X + 10 < connector2.Point.X)
				{
					x = connector2.Point.X;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else
				{
					x = connector1.Point.X + 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 右对左

			else if (connector1.ConnectorDirection == ConnectorDirection.Right && connector2.ConnectorDirection == ConnectorDirection.Left)
			{
				if (connector1.Point.X + 10 >= connector2.Point.X)
				{
					x = connector1.Point.X + 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X - 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else
				{
					x = connector1.Point.X + 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 上对上

			else if (connector1.ConnectorDirection == ConnectorDirection.Up && connector2.ConnectorDirection == ConnectorDirection.Up)
			{
				x = connector1.Point.X;
				y = Math.Min(connector1.Point.Y - 10, connector2.Point.Y - 20);
				connectors.Add(new Connector(new DiagramPoint(x, y)));

				x = connector2.Point.X;
				connectors.Add(new Connector(new DiagramPoint(x, y)));
			}

			#endregion

			#region 上对右

			else if (connector1.ConnectorDirection == ConnectorDirection.Up && connector2.ConnectorDirection == ConnectorDirection.Right)
			{
				if (connector1.Point.Y > connector2.Point.Y && connector1.Point.X > connector2.Point.X)
				{
					x = connector1.Point.X;
					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y > connector2.Point.Y)
				{
					x = connector1.Point.X;
					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y <= connector2.Point.Y)
				{
					x = connector1.Point.X;
					y = connector1.Point.Y - 10;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 上对下

			else if (connector1.ConnectorDirection == ConnectorDirection.Up && connector2.ConnectorDirection == ConnectorDirection.Down)
			{
				if (connector1.Point.Y > connector2.Point.Y && connector1.Point.X != connector2.Point.X)
				{
					x = connector1.Point.X;
					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y < connector2.Point.Y && connector1.Point.X != connector2.Point.X)
				{
					x = connector1.Point.X;
					y = connector1.Point.Y - 10;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = (connector1.Point.X + connector2.Point.X) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 上对左

			else if (connector1.ConnectorDirection == ConnectorDirection.Up && connector2.ConnectorDirection == ConnectorDirection.Left)
			{
				if (connector1.Point.Y > connector2.Point.Y && connector1.Point.X < connector2.Point.X)
				{
					x = connector1.Point.X;
					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y > connector2.Point.Y)
				{
					x = connector1.Point.X;
					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X - 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y <= connector2.Point.Y)
				{
					x = connector1.Point.X;
					y = connector1.Point.Y - 10;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X - 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 左对上

			else if (connector1.ConnectorDirection == ConnectorDirection.Left && connector2.ConnectorDirection == ConnectorDirection.Up)
			{
				if (connector1.Point.Y < connector2.Point.Y && connector1.Point.X - 10 >= connector2.Point.X)
				{
					x = connector2.Point.X;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y < connector2.Point.Y)
				{
					x = connector1.Point.X - 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.Y > connector2.Point.Y)
				{
					x = connector1.Point.X - 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y - 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 左对右

			else if (connector1.ConnectorDirection == ConnectorDirection.Left && connector2.ConnectorDirection == ConnectorDirection.Right)
			{
				if (connector1.Point.X - 10 >= connector2.Point.X)
				{
					x = (connector1.Point.X + connector2.Point.X) / 2;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else
				{
					x = connector1.Point.X - 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = (connector1.Point.Y + connector2.Point.Y) / 2;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 左对下

			else if (connector1.ConnectorDirection == ConnectorDirection.Left && connector2.ConnectorDirection == ConnectorDirection.Down)
			{
				if (connector1.Point.Y > connector2.Point.Y && connector1.Point.X > connector2.Point.X)
				{
					x = connector2.Point.X;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
				else if (connector1.Point.X != connector2.Point.X)
				{
					x = connector1.Point.X - 10;
					y = connector1.Point.Y;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					y = connector2.Point.Y + 20;
					connectors.Add(new Connector(new DiagramPoint(x, y)));

					x = connector2.Point.X;
					connectors.Add(new Connector(new DiagramPoint(x, y)));
				}
			}

			#endregion

			#region 左对左

			else if (connector1.ConnectorDirection == ConnectorDirection.Left && connector2.ConnectorDirection == ConnectorDirection.Left)
			{
				x = Math.Min(connector1.Point.X - 10, connector2.Point.X - 20);
				y = connector1.Point.Y;
				connectors.Add(new Connector(new DiagramPoint(x, y)));

				y = connector2.Point.Y;
				connectors.Add(new Connector(new DiagramPoint(x, y)));
			}

			#endregion

			connectors.Add(this.to);
			Connectors = connectors;

		}
		#endregion

		#region 重写方法
        /// <summary>
        /// 所属的流程图控件改变就将出发点 终点的流程图控件赋予
        /// </summary>
		protected override void SiteChanged()
		{
			if (from != null)
				this.from.Site = site;
			if (to != null)
				this.to.Site = site;
		}

        /// <summary>
        /// 在画布上绘制连接
        /// </summary>
        /// <param name="g"></param>
        public override void Paint(System.Drawing.Graphics g)
		{
			if (site == null) return;

			Pen p = new Pen(UseBackColor ? this.Color : this.site.LineColor);
			if (isSelected)
			{
				p.Color = UseBackColor ? this.LineSelectedColor : this.site.LineSelectedColor;
				p.Width = 2F;
			}
			else if (Hovered)
			{
				p.Color = UseBackColor ? this.LineHoveredColor : this.site.LineHoveredColor;
				p.Width = 2F;
			}

			Connectors[0].Paint(g);
			for (int i = 1; i < Connectors.Count - 1; i++)
			{
				g.DrawLine(p,
					Connectors[i - 1].Point.X + this.site.ViewOriginPoint.GetPoint().X,
					Connectors[i - 1].Point.Y + this.site.ViewOriginPoint.GetPoint().Y,
					Connectors[i].Point.X + this.site.ViewOriginPoint.GetPoint().X,
					Connectors[i].Point.Y + this.site.ViewOriginPoint.GetPoint().Y);
				Connectors[i].Paint(g);
			}

			Connectors[Connectors.Count - 1].Paint(g);
			p.CustomEndCap = new AdjustableArrowCap(p.Width * 5, p.Width * 5, true);
			g.DrawLine(p,
				Connectors[Connectors.Count - 2].Point.X + this.site.ViewOriginPoint.GetPoint().X,
				Connectors[Connectors.Count - 2].Point.Y + this.site.ViewOriginPoint.GetPoint().Y,
				Connectors[Connectors.Count - 1].Point.X + this.site.ViewOriginPoint.GetPoint().X,
				Connectors[Connectors.Count - 1].Point.Y + this.site.ViewOriginPoint.GetPoint().Y);
		}
        /// <summary>
        /// 使连接无效
        /// </summary>
        public override void Invalidate()
		{
			Rectangle f = new Rectangle(from.Point.GetPoint(), new Size(10, 10));
			f.X += this.site.ViewOriginPoint.GetPoint().X;
			f.Y += this.site.ViewOriginPoint.GetPoint().Y;
			Rectangle t = new Rectangle(to.Point.GetPoint(), new Size(10, 10));
			t.X += this.site.ViewOriginPoint.GetPoint().X;
			t.Y += this.site.ViewOriginPoint.GetPoint().Y;
			site.Invalidate(Rectangle.Union(f, t));
		}

        /// <summary>
        /// 测试鼠标是否点击此连接
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public override bool Hit(Point p)
		{
			p.Offset(-this.site.ViewOriginPoint.GetPoint().X, -this.site.ViewOriginPoint.GetPoint().Y);
			for (int i = 1; i < Connectors.Count; i++)
			{
				if (GetPointIsInLine(p, Connectors[i - 1].Point.GetPoint(), Connectors[i].Point.GetPoint(), 3))
				{
					return true;
				}
			}
			return false;
		}

		/// <summary>
		/// 判断点是否在直线上
		/// </summary>
		/// <param name="pf"></param>
		/// <param name="p1"></param>
		/// <param name="p2"></param>
		/// <param name="range">判断的的误差，不需要误差则赋值0</param>
		/// <returns></returns>
		private bool GetPointIsInLine(Point pf, Point p1, Point p2, double range)
		{
			double cross = (p2.X - p1.X) * (pf.X - p1.X) + (p2.Y - p1.Y) * (pf.Y - p1.Y);
			if (cross <= 0) return false;
			double d2 = (p2.X - p1.X) * (p2.X - p1.X) + (p2.Y - p1.Y) * (p2.Y - p1.Y);
			if (cross >= d2) return false;

			double r = cross / d2;
			double px = p1.X + (p2.X - p1.X) * r;
			double py = p1.Y + (p2.Y - p1.Y) * r;

			//判断距离是否小于误差
			return Math.Sqrt((pf.X - px) * (pf.X - px) + (py - pf.Y) * (py - pf.Y)) <= range;
		}

        /// <summary>
        /// 移动连接
        /// </summary>
        /// <param name="p"></param>
        public override void Move(Point p)
		{
		}


		#endregion

	}
    /// <summary>
    /// 实体类，工具类 连接点类 连接边类 继承自这个实体类
    /// </summary>
	public abstract class Entity : BindableBase
	{
        #region Fields
        /// <summary>
        /// 实体类，工具类 连接点类 连接边类 继承自这个实体类，当前实体是否被鼠标悬停
        /// </summary>
        protected internal bool Hovered = false;
        /// <summary>
        /// 实体类，工具类 连接点类 连接边类 继承自这个实体类，实体所属的流程图控件
        /// </summary>
        protected Canvas site;
        /// <summary>
        /// 实体类，工具类 连接点类 连接边类 继承自这个实体类，实体是否被选择
        /// </summary>
        protected bool isSelected = false;

        /// <summary>
        /// 实体类，工具类 连接点类 连接边类 继承自这个实体类，默认字体
        /// </summary>
        protected Font Font = new Font("Verdana", 10F);

        /// <summary>
        /// 实体类，工具类 连接点类 连接边类 继承自这个实体类，默认黑色笔
        /// </summary>
        protected Pen BlackPen = new Pen(Brushes.Black, 1F);

        #endregion

        #region 属性
        /// <summary>
        /// 实体类，工具类 连接点类 连接边类 继承自这个实体类，实体ID
        /// </summary>
        [Browsable(false)]
		public string ObjectId { get; set; } = Guid.NewGuid().ToString();

        /// <summary>
        /// 实体类，工具类 连接点类 连接边类 继承自这个实体类，实体是否被选择 画布使用	
        /// </summary>
        [Browsable(false)]
		[JsonIgnore]
		public bool IsSelected
		{
			get { return isSelected; }
			set { isSelected = value; }
		}
        /// <summary>
        ///实体类，工具类 连接点类 连接边类 继承自这个实体类，获取或设置实体所属的画布
        /// </summary>
        [Browsable(false)]
		[JsonIgnore]
		public Canvas Site
		{
			get
			{
				return site;
			}
			set
			{
				site = value;
				SiteChanged();
			}
		}

		#endregion

		#region Constructor
		
		public Entity()
		{
		}

        /// <summary>
        /// 构造函数时设置实体所属的画布
        /// </summary>
        /// <param name="site">实体所属的画布</param>
        public Entity(Canvas site)
		{
			this.site = site;
		}


		#endregion

		#region 虚方法，继承者实现

		protected virtual void SiteChanged()
		{
		}

		/// <summary>
		/// 在控件上绘制实体
		/// </summary>
		/// <param name="g">the graphics object to paint on</param>
		public abstract void Paint(Graphics g);
		/// <summary>
		/// 测试形状是否被鼠标击中
		/// </summary>
		/// <param name="p"></param>
		/// <returns></returns>
		public abstract bool Hit(Point p);
		/// <summary>
		///使实体无效
		/// </summary>
		public abstract void Invalidate();
		/// <summary>
		/// 在画布上移动实体
		/// </summary>
		/// <param name="p">the shifting vector, not an absolute position!</param>
		public abstract void Move(Point p);

		#endregion
	}
    /// <summary>
    /// 双向绑定类，主要实现接口事件
    /// </summary>
    public abstract class BindableBase : INotifyPropertyChanged
	{
        /// <summary>
        /// 自定义事件， 在属性值更改时发生
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// 检查属性是否已与所需值匹配。设置属性和仅在必要时通知侦听器。
        /// </summary>
        /// <typeparam name="T">属性的类型。</typeparam>
        /// <param name="storage">对具有getter和setter的属性的引用。</param>
        /// <param name="value">属性的所需值。</param>
        /// <param name="propertyName">用于通知侦听器的属性的名称。 此值是可选的，可以在从支持CallerMemberName的编译器调用时自动提供。</param>
        /// <returns>如果值已更改，则为True；如果现有值与设计值匹配，则为false</returns>
        protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null)
		{
			if (EqualityComparer<T>.Default.Equals(storage, value))
				return false;
			storage = value;
			this.RaisePropertyChanged(propertyName);
			return true;
		}

		/// <summary>
		/// Checks if a property already matches a desired value. Sets the property and
		/// notifies listeners only when necessary.
		/// </summary>
		/// <typeparam name="T">Type of the property.</typeparam>
		/// <param name="storage">Reference to a property with both getter and setter.</param>
		/// <param name="value">Desired value for the property.</param>
		/// <param name="propertyName">Name of the property used to notify listeners. This
		/// value is optional and can be provided automatically when invoked from compilers that
		/// support CallerMemberName.</param>
		/// <param name="onChanged">Action that is called after the property value has been changed.</param>
		/// <returns>True if the value was changed, false if the existing value matched the
		/// desired value.</returns>
		protected virtual bool SetProperty<T>(
		  ref T storage,
		  T value,
		  Action onChanged,
		  [CallerMemberName] string propertyName = null)
		{
			if (EqualityComparer<T>.Default.Equals(storage, value))
				return false;
			storage = value;
			if (onChanged != null)
				onChanged();
			this.RaisePropertyChanged(propertyName);
			return true;
		}

		/// <summary>Raises this object's PropertyChanged event.</summary>
		/// <param name="propertyName">Name of the property used to notify listeners. This
		/// value is optional and can be provided automatically when invoked from compilers
		/// that support <see cref="T:System.Runtime.CompilerServices.CallerMemberNameAttribute" />.</param>
		protected void RaisePropertyChanged([CallerMemberName] string propertyName = null) => this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));

		/// <summary>Raises this object's PropertyChanged event.</summary>
		/// <param name="args">The PropertyChangedEventArgs</param>
		protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
		{
			PropertyChangedEventHandler propertyChanged = this.PropertyChanged;
			if (propertyChanged == null)
				return;
			propertyChanged((object)this, args);
		}
	}
    /// <summary>
    /// 连接器类信息
    /// </summary>
    public class Connector : Entity
	{
		#region Constructor
		/// <summary>
		/// 构造函数
		/// </summary>
		public Connector()
		{
			attachedConnectors = new List<Connector>();
		}

        /// <summary>
        /// 构造函数，传递其位置
        /// </summary>
        /// <param name="p"></param>
        public Connector(DiagramPoint p)
		{
			attachedConnectors = new List<Connector>();
			Point = p;
		}

        #endregion

        #region 连接边的自定义事件，用于位置改变后边的位置绘制

        /// <summary>
        /// 连接边的自定义事件，用于位置改变后边的位置绘制
        /// </summary>
        public event EventHandler<LocationEventArgs> LocationChanged;
        /// <summary>
        /// 连接边的自定义事件，用于位置改变后边的位置绘制
        /// </summary>
        /// <param name="e"></param>
		private void OnLocationChanged(LocationEventArgs e)
		{
			LocationChanged?.Invoke(this, e);
		}
        /// <summary>
        /// 连接边的自定义事件，用于位置改变后边的位置绘制
        /// </summary>
		public event EventHandler<AttachedToChangedEventArgs> AttachedToChanged;
        /// <summary>
        /// 连接边的自定义事件，用于位置改变后边的位置绘制
        /// </summary>
        /// <param name="e"></param>
		private void OnAttachedToChanged(AttachedToChangedEventArgs e)
		{
			AttachedToChanged?.Invoke(this, e);
		}

		#endregion

		#region Fields
		/// <summary>
		/// 此连接器的位置
		/// </summary>
		protected DiagramPoint point;
		/// <summary>
		/// 以我为目标的连接点，可能有多个
		/// </summary>
		protected List<Connector> attachedConnectors;
		/// <summary>
		/// 以我为出发点的连接点,只有一个
		/// </summary>
		protected Connector attachedTo;
        /// <summary>
        /// 此连接器的名称
        /// </summary>
        protected string name;

		private ConnectorDirection? _connectorDirection = null;
		private string _ownerId;

        #endregion

        #region Properties
        /// <summary>
        /// 此连接器的主人,可能是Tool或Connection
        /// </summary>
        [JsonIgnore]
		public Entity OwnerEntity { get; set; }

        /// <summary>
        /// 在Tool里的索引,0,1,2,3,上下左右
        /// </summary>
        public int ConnectorsIndexOfContainEntity { get; set; } = -1;
        /// <summary>
        /// 此连接器的ID
        /// </summary>
		[Browsable(false)]
		public string OwnerID
		{
			get => _ownerId;
			set { _ownerId = value; }
		}

        /// <summary>
        /// 此连接器的名称
        /// </summary>
        public string Name
		{
			get { return name; }
			set { name = value; }
		}

		[Browsable(false)]
		public int Index { get; set; } = 0;
        /// <summary>
        /// 连接器方向
        /// </summary>
		public ConnectorDirection ConnectorDirection
		{
			get
			{
				if (_connectorDirection != null && point != null)
					point.ConnectorDirection = (ConnectorDirection)_connectorDirection;

				if (point == null)
					return _connectorDirection ?? ConnectorDirection.Up;

				return point.ConnectorDirection;
			}
			set
			{
				if (point != null)
					point.ConnectorDirection = value;
				_connectorDirection = value;
			}
		}

        /// <summary>
        /// 连接器附件
        /// </summary>
		public Connector AttachedTo
		{
			get { return attachedTo; }
			set
			{
				if (attachedTo == null)
				{
					return;
				}
				attachedTo = value;
				point = attachedTo.point.Copy();
				_connectorDirection = attachedTo.ConnectorDirection;
				OnAttachedToChanged(new AttachedToChangedEventArgs() { New = value });
			}
		}

        /// <summary>
        /// 此连接器的位置
        /// </summary>
        public DiagramPoint Point
		{
			get { return point; }
			set { point = value; if (_connectorDirection != null) point.ConnectorDirection = (ConnectorDirection)_connectorDirection; }
		}

        #endregion

        #region 虚方法的实现
        /// <summary>
        /// 在画布上绘制连接器
        /// </summary>
        /// <param name="g"></param>
        public override void Paint(Graphics g)
		{
			if (Hovered && this.site != null)
				g.FillRectangle(Brushes.Cyan, point.X + this.site.ViewOriginPoint.GetPoint().X - 10, point.Y + this.site.ViewOriginPoint.GetPoint().Y - 10, 20, 20);
			//else
			//	g.FillRectangle(Brushes.Green, point.X + this.site.ViewOriginPoint.X - 2, point.Y + this.site.ViewOriginPoint.Y - 2, 4, 4);
		}

        /// <summary>
        /// 测试鼠标是否击中此连接器
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public override bool Hit(Point p)
		{
			p.X = p.X - this.site.ViewOriginPoint.GetPoint().X;
			p.Y = p.Y - this.site.ViewOriginPoint.GetPoint().Y;

			Point a = p;
			Point b = point.GetPoint();
			b.Offset(-7, -7);
			//a.Offset(-1,-1);
			Rectangle r = new Rectangle(a, new Size(0, 0));
			Rectangle d = new Rectangle(b, new Size(15, 15));
			return d.Contains(r);
		}

        /// <summary>
        /// 使连接器无效
        /// </summary>
        public override void Invalidate()
		{
			Point p = point.GetPoint();
			p.X += this.site.ViewOriginPoint.GetPoint().X;
			p.Y += this.site.ViewOriginPoint.GetPoint().Y;
			p.Offset(-5, -5);
			site.Invalidate(new Rectangle(p, new Size(10, 10)));
		}

        /// <summary>
        /// 使用给定的移位向量移动连接器
        /// </summary>
        /// <param name="p"></param>
        public override void Move(Point p)
		{
			OnLocationChanged(new LocationEventArgs() { OffsetX = p.X, OffsetY = p.Y });
			this.point.X = this.point.X + p.X;
			this.point.Y = this.point.Y + p.Y;
			for (int k = 0; k < attachedConnectors.Count; k++)
				attachedConnectors[k].Move(p);
		}

        /// <summary>
        /// 附加连接器
        /// </summary>
        /// <param name="c"></param>
        public void AttachConnector(Connector c)
		{
			//remove from the previous, if any
			if (c.attachedTo != null)
			{
				c.attachedTo.attachedConnectors.Remove(c);
			}
			attachedConnectors.Add(c);
			c.AttachedTo = this;

		}

        /// <summary>
        /// 分离连接器
        /// </summary>
        /// <param name="c"></param>
        public void DetachConnector(Connector c)
		{
			attachedConnectors.Remove(c);
		}

        /// <summary>
        /// 将此连接器与任何其他连接器断开
        /// </summary>
        public void Release()
		{
			if (this.attachedTo != null)
			{
				this.attachedTo.attachedConnectors.Remove(this);
				this.AttachedTo = null;
			}

		}

		#endregion
	}
    /// <summary>
    /// 位置事件
    /// </summary>
	public class LocationEventArgs : EventArgs
	{
		public int OffsetX = 0;
		public int OffsetY = 0;
	}
    /// <summary>
    /// 附件更改事件
    /// </summary>
	public class AttachedToChangedEventArgs : EventArgs
	{
		public Connector New { get; set; }
	}
    /// <summary>
    /// 连接器方向枚举
    /// </summary>
    public enum ConnectorDirection
	{
		Left,
		Down,
		Right,
		Up
	}
    /// <summary>
    /// 存储工具类
    /// </summary>
    public class ToolMgr
	{
		#region 单例
		private static readonly Lazy<ToolMgr> Instance = new Lazy<ToolMgr>(() => new ToolMgr());

		private ToolMgr()
		{
			ToolDirPath = Environment.CurrentDirectory + "\\Tools\\";
            if (!Directory.Exists(ToolDirPath))
            {
                Directory.CreateDirectory(ToolDirPath);
            }
            Tools = new List<ActionItem>();
			//Images = new ConcurrentDictionary<string, Bitmap>();
		}
		public static ToolMgr Ins { get; } = Instance.Value;
        #endregion 单例
        /// <summary>
        /// 存储的工具类
        /// </summary>
        public List<ActionItem> Tools;
		//public ConcurrentDictionary<string, Bitmap> Images;
		public string ToolDirPath { get; set; }
        /// <summary>
        /// 加载工具
        /// </summary>
		public void LoadTools()
		{
			Tools.Clear();
			var files = Directory.GetFiles(ToolDirPath, "*.tool");
			foreach (var file in files)
			{
				try
				{
					var tool = Json.LoadExt<ActionItem>(file);
					if (tool != null)
					{
						string iconPath = ToolDirPath + tool.Icon;
						//Image img;
						if (File.Exists(iconPath))
						{
							//img = Image.FromFile(iconPath);

						}
						else
						{
							//img = Resources.默认工具;
							//tool.Icon = Resources.默认工具.ToString();
						}
						//img = ResizeImageHelper.resizeImage(img, new Size(32, 32));
						//Images.TryAdd(tool.Icon, (Bitmap)img);
						Tools.Add(tool);
					}
				}
				catch (Exception e)
				{
					Console.WriteLine($"加载工具时发现错误的工具{e.Message}");

				}
			}

		}
        /// <summary>
        /// 保存工具
        /// </summary>
        /// <param name="tool"></param>
		public void SaveTool(ActionItem tool)
		{
            Json.SaveExt<ActionItem>(ToolDirPath + tool.ItemName + ".tool", tool);
		}

	}
    /// <summary>
    /// 工具信息类
    /// </summary>
    public class ActionItem : Entity
    {
        #region Protect

        /// <summary>
        /// 事件聚合器
        /// </summary>
        protected EventMgr Em;

        #endregion Protect

        #region 构造与析构

        public ActionItem()
        {
            Em = EventMgr.Ins;
            StepID = Guid.NewGuid();
            Parms = new List<MethodParms>();
            ParaTypes = new List<string>();
            ParaNames = new List<string>();
            connectors = new List<Connector>();
            ToolRectangle = new Rectangle(0, 0, 120, 70)
            {
                Height = 33
            };
        }

        #endregion 构造与析构

        #region 私有字段      
        private Bitmap _bitIcon;
        private string _itemName;
        #endregion 私有字段

        #region 公有属性

        #region  该字段用于存储坐标位，以便combox选择定位

        public DiagramPoint ViewOriginPoint { get; set; } = new DiagramPoint(0, 0);

        #endregion

        #region 该字段用于脚本的内容编辑
        /// <summary>
        /// 脚本内容
        /// </summary>
        [Browsable(true), Editor(typeof(propertyScriptEdit), typeof(UITypeEditor))]
        public string Code { get; set; }

        /// <summary>
        /// 主要用于脚本工具中在属性控件当中显示内容使用
        /// </summary>
        public bool IsScript=false;

        #endregion

        #region 该字段用于逻辑内容编辑

        /// <summary>
        /// 主要用于逻辑工具中在属性控件当中显示内容使用
        /// </summary>
        public bool IsLogic = false;

        #endregion

        #region  该字段用于确定是否是构造方法

        public bool IsConstructor = false;

        #endregion

        /// <summary>
        /// 工具信息类，工具来自哪个Dll
        /// </summary>
        [Browsable(true), Description("工具来自哪个Dll"), Category("程序集"), ReadOnly(true)]
        public string Dll
        {
            get { return _dll; }
            set { _dll = value; }
        }
        private string _dll;

        /// <summary>
        /// 工具信息类，类名
        /// </summary>
        [Browsable(true), Description("类名"), Category("程序集"), ReadOnly(true)]
        public string TypeName
        {
            get { return _typeName; }
            set { _typeName = value; }
        }
        private string _typeName;

        /// <summary>
        /// 工具信息类，方法名
        /// </summary>
        [Browsable(true), Description("方法名"), Category("程序集"), ReadOnly(true)]
        public string MethodName
        {
            get { return _methodName; }
            set { _methodName = value; }
        }
        private string _methodName;

        /// <summary>
        /// 工具信息类，参数列表
        /// </summary>
        [Browsable(true), Description("参数列表"), Category("程序集"), ReadOnly(true)]
        public List<MethodParms> Parms
        {
            get { return _parms; }
            set { _parms = value; }
        }
        private List<MethodParms> _parms;
        /// <summary>
        /// 工具信息类，参数列表类型
        /// </summary>
        [Browsable(true), Description("参数列表类型"), Category("程序集"), ReadOnly(true)]
        public List<string> ParaTypes
        {
            get { return _paraTypes; }
            set { _paraTypes = value; }
        }
        private List<string> _paraTypes;

        /// <summary>
        /// 工具信息类，参数列表名称
        /// </summary>
        [Browsable(true), Description("参数列表名称"), Category("程序集"), ReadOnly(true)]
        public List<string> ParaNames
        {
            get { return _paraNames; }
            set { _paraNames = value; }
        }
        private List<string> _paraNames;

        /// <summary>
        /// 工具信息类，参数列表的Guid
        /// </summary>
        [Browsable(true), Description("参数列表的Guid"), Category("程序集"), ReadOnly(true)]
        public List<string> VarIDs { get; set; }

        /// <summary>
        /// 工具信息类，执行方法的对象
        /// </summary>
        [Browsable(true), Description("执行方法的对象"), Category("程序集"), ReadOnly(true)]
        [JsonIgnore]
        public object Obj
        {
            get { return _obj; }
            set { _obj = value; }
        }
        private object _obj;

        /// <summary>
        /// 工具信息类，执行方法的对象名称
        /// </summary>
        [Browsable(true), Description("执行方法的对象名称"), Category("程序集"), ReadOnly(true)]
        public string ObjName
        {
            get { return _objName; }
            set { _objName = value; }
        }
        private string _objName;

        /// <summary>
        /// 工具信息类，返回值类型是否是静态的
        /// </summary>
        [Browsable(true), Description("返回值类型是否是静态的"), Category("程序集"), ReadOnly(true)]
        public bool IsStatic
        {
            get { return _isStatic; }
            set { _isStatic = value; }
        }
        private bool _isStatic;

        /// <summary>
        /// 工具信息类，返回值类型
        /// </summary>
        [Browsable(true), Description("返回值类型"), Category("程序集"), ReadOnly(true)]
        public string ReturnType
        {
            get { return _returnType; }
            set { _returnType = value; }
        }
        private string _returnType;

        /// <summary>
        /// 工具信息类，返回值对象名称
        /// </summary>
        [Browsable(true), Description("返回值对象名称"), Category("程序集"), ReadOnly(true)]
        public string ReturnObjName
        {
            get { return _returnObjName; }
            set { _returnObjName = value; }
        }
        private string _returnObjName;

        /// <summary>
        /// 工具信息类，工具箱里的分组
        /// </summary>
        [Browsable(true), Description("工具箱里的分组"), Category("工具箱"), ReadOnly(true)]
        public string Group
        {
            get { return _group; }
            set { _group = value; }
        }
        private string _group;

        /// <summary>
        /// 工具信息类，工具图标
        /// </summary>
        [Browsable(true), Description("工具图标"), Category("公用"), ReadOnly(true)]
        public string Icon
        {
            get { return _icon; }
            set { _icon = value; }
        }
        private string _icon;

        /// <summary>
        /// 工具信息类，名称
        /// </summary>
        [Browsable(true), Description("名称"), Category("公用"), ReadOnly(false)]
        public string ItemName
        {
            get { return text; }
            set
            {
                SetProperty(ref text, value);
            }
        }

        /// <summary>
        /// 工具信息类，序号
        /// </summary>
        [Browsable(true), Description("序号"), Category("编辑界面"), ReadOnly(true)]
        public int Index
        {
            get { return _index; }
            set
            {
                SetProperty(ref _index, value);
            }
        }
        private int _index;

        /// <summary>
        /// 工具信息类，是否启用
        /// </summary>
        [Browsable(true), Description("是否启用"), Category("编辑界面")]
        public bool InUse
        {
            get { return _inUse; }
            set { SetProperty(ref _inUse, value); }
        }
        private bool _inUse;

        //[JsonIgnore]
        //public Bitmap BitIcon
        //{
        //    get
        //    {
        //        if (ToolMgr.Ins.Images.ContainsKey(Icon))
        //        {
        //            _bitIcon = ToolMgr.Ins.Images[Icon];
        //        }
        //        return _bitIcon;
        //    }
        //    set { _bitIcon = value; }
        //}

        /// <summary>
        /// 工具信息类，描述
        /// </summary>
        [Browsable(true), Description("描述"), Category("编辑界面")]
        public string Description
        {
            get { return _description; }
            set { SetProperty(ref _description, value); }
        }
        private string _description;

        /// <summary>
        /// 工具信息类，执行状态
        /// </summary>
        [Browsable(true), Description("执行状态"), Category("编辑界面"), ReadOnly(true)]
        public string Status
        {
            get { return _status; }
            set
            {
                SetProperty(ref _status, value);
            }
        }
        private string _status;

        /// <summary>
        /// 工具信息类，耗时
        /// </summary>
        [Browsable(true), Description("耗时"), Category("编辑界面"), ReadOnly(true)]
        public string Time
        {
            get
            {
                return _time;
            }
            set
            {
                SetProperty(ref _time, value);
            }
        }
        private string _time;

        /// <summary>
        /// 工具信息类，备用属性,用于不想创建属性时，object类型
        /// </summary>
        [Browsable(true), Description("备用属性,用于不想创建属性时"), Category("Tag"), ReadOnly(false)]
        public object Tag
        {
            get { return _tag; }
            set { _tag = value; }
        }
        private object _tag;

        /// <summary>
        /// 工具信息类，执行前等待
        /// </summary>
        [Browsable(true), Description("执行前等待"), Category("时间")]
        public int BeforeWait
        {
            get { return _beforeWait; }
            set { _beforeWait = value; }
        }
        private int _beforeWait;

        /// <summary>
        /// 工具信息类，执行后等待
        /// </summary>
        [Browsable(true), Description("执行后等待"), Category("时间")]
        public int AfterWait
        {
            get { return _afterWait; }
            set { _afterWait = value; }
        }
        private int _afterWait;

        /// <summary>
        /// 工具信息类，超时时间
        /// </summary>
        [Browsable(true), Description("超时时间"), Category("时间")]
        public int OverTime
        {
            get { return _overTime; }
            set { _overTime = value; }
        }
        private int _overTime;

        /// <summary>
        /// 工具信息类，步骤ID
        /// </summary>
        [Browsable(true), Description("步骤ID"), Category("跳转"), ReadOnly(true)]
        public Guid StepID
        {
            get { return _stepId; }
            set { _stepId = value; }
        }
        private Guid _stepId;

        /// <summary>
        /// 工具信息类，跳转标签
        /// </summary>
        [Browsable(true), Description("跳转标签"), Category("跳转"), ReadOnly(true)]
        public string GoToLabel
        {
            get
            {
                _goToLabel = Index + ItemName;
                return _goToLabel;
            }
            set { _goToLabel = value; }
        }
        private string _goToLabel;

        /// <summary>
        /// 工具信息类，启用成功跳转
        /// </summary>
        [Browsable(true), Description("启用成功跳转"), Category("跳转")]
        public bool EnableSuccessGoto
        {
            get { return _enableSuccessGoto; }
            set { _enableSuccessGoto = value; }
        }
        private bool _enableSuccessGoto;

        /// <summary>
        /// 工具信息类，启用失败跳转
        /// </summary>
        [Browsable(true), Description("启用失败跳转"), Category("跳转")]
        public bool EnableFailedGoto
        {
            get { return _enableFailedGoto; }
            set { _enableFailedGoto = value; }
        }
        private bool _enableFailedGoto;

        /// <summary>
        /// 工具信息类，成功后跳转位置ID
        /// </summary>
        [Browsable(true), Description("成功后跳转位置ID"), Category("跳转"), ReadOnly(true)]
        public Guid SuccessStepID
        {
            get { return _successStepId; }
            set { _successStepId = value; }
        }
        private Guid _successStepId;

        /// <summary>
        /// 工具信息类，失败后跳转位置ID
        /// </summary>
        [Browsable(true), Description("失败后跳转位置ID"), Category("跳转"), ReadOnly(true)]
        public Guid FailStepID
        {
            get { return _failStepId; }
            set { _failStepId = value; }
        }
        private Guid _failStepId;

        /// <summary>
        /// 工具信息类，失败后停止此流程
        /// </summary>
        [Browsable(true), Description("失败后停止此流程"), Category("跳转")]
        public bool FailStopFlow
        {
            get { return _failStopFlow; }
            set { _failStopFlow = value; }
        }
        private bool _failStopFlow;

        /// <summary>
        /// 工具信息类，失败后停止所有流程
        /// </summary>
        [Browsable(true), Description("失败后停止所有流程"), Category("跳转")]
        public bool FailStopAllFlow
        {
            get { return _failStopAllFlow; }
            set { _failStopAllFlow = value; }
        }
        private bool _failStopAllFlow;

        /// <summary>
        /// 工具信息类，成功后停止此流程
        /// </summary>
        [Browsable(true), Description("成功后停止此流程"), Category("跳转")]
        public bool SuccessStopFlow
        {
            get { return _successStopFlow; }
            set { _successStopFlow = value; }
        }
        private bool _successStopFlow;

        /// <summary>
        /// 工具信息类，成功后停止所有流程
        /// </summary>
        [Browsable(true), Description("成功后停止所有流程"), Category("跳转")]
        public bool SuccessStopAllFlow
        {
            get { return _successStopAllFlow; }
            set { _successStopAllFlow = value; }
        }
        private bool _successStopAllFlow;

        /// <summary>
        /// 工具信息类，方法的对象
        /// </summary>
        [Browsable(false)]
        public string ObjGuid { get; set; } = Guid.NewGuid().ToString();

        /// <summary>
        /// 工具信息类，方法返回的对象
        /// </summary>
        [Browsable(false)]
        public string ReturnObjGuid { get; set; } = Guid.NewGuid().ToString();

        /// <summary>
        /// 工具信息类，
        /// </summary>
        [JsonIgnore, Browsable(false)]
        public int NextIndex { get; set; }

        /// <summary>
        /// 工具信息类，
        /// </summary>
        [JsonIgnore, Browsable(false)]
        public Flow Flow { get; set; }

        /// <summary>
        /// 工具信息类，
        /// </summary>
        [JsonIgnore, Browsable(false)]
        public int CurrentIndex { get; set; }

        /// <summary>
        /// 工具信息类，只要有一个前置任务执行完就执行此任务，默认是等待所有前置任务执行完
        /// </summary>
        [Browsable(true), Description("只要有一个前置任务执行完就执行此任务，默认是等待所有前置任务执行完"), Category("任务调度")]
        public bool WaitAny
        {
            get { return _waitAny; }
            set { SetProperty(ref _waitAny, value); }
        }
        private bool _waitAny;

        //private bool _isRunning;
        //[Browsable(true), Description("标记任务是否正在执行中"), Category("任务调度"),ReadOnly(true)]
        //public bool IsRunning
        //{
        //    get { return _isRunning; }
        //    set { SetProperty(ref _isRunning, value); }
        //}
        //private bool _isRuned;
        //[Browsable(true), Description("标记任务是否已执行"), Category("任务调度"),ReadOnly(true)]
        //public bool IsRuned
        //{
        //    get { return _isRuned; }
        //    set { SetProperty(ref _isRuned, value); }
        //}

        #endregion 公有属性 

        #region 公有方法

        /// <summary>
        /// 复制工具
        /// </summary>
        /// <returns></returns>
        public virtual dynamic CopyFromTool()
        {
            dynamic actionItem = Activator.CreateInstance(this.GetType());//创建对象
            actionItem.Dll = this.Dll;
            actionItem.ItemName = this.ItemName;
            actionItem.TypeName = this.TypeName;
            actionItem.MethodName = this.MethodName;
            actionItem.IsStatic = this.IsStatic;
            actionItem.Icon = this.Icon;
            actionItem.ReturnType = this.ReturnType;
            ParaTypes.ForEach(item => actionItem.ParaTypes.Add(item));
            for (int i = 0; i < ParaTypes.Count; i++)
            {
                string item = ParaTypes[i];
                var methodparm = new MethodParms() { Name = ParaNames[i], Type = item, InputOrSelect = true };
                actionItem.Parms.Add(methodparm);
            }
            return actionItem;
        }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <returns></returns>
        public virtual bool Initilize()
        {
            InitilizeMethod();
            return true;
        }

        //public virtual UIPage GetParmsPage()
        //{
        //    var method = InitilizeMethod();
        //    if (method == null) return null;

        //    ParaPage pageAtt = (ParaPage)method.GetCustomAttribute(typeof(ParaPage));
        //    if (pageAtt != null)
        //    {
        //        return pageAtt.GetParaPage(this);
        //    }

        //    return new FrmActionItem(this);
        //}

        public virtual UIForm GetConfigForm()
        {
            return null;
        }

        /// <summary>
        /// 工具运行
        /// </summary>
        /// <returns></returns>
        [ReflectAble]
        public virtual bool Run()
        {
            Status = "开始执行...";
            //运行前做一些事情
            var sw = Stopwatch.StartNew();
            if (BeforeWait > 0) Thread.Sleep(BeforeWait);
            //执行具体的方法
            var result = RunMethod();
            if (this.Flow != null) NextActionItemIndex(result);

            Status = result ? "成功" : "失败";
            //运行后做一些事情
            if (AfterWait > 0) Thread.Sleep(AfterWait);

            Time = sw.ElapsedMilliseconds.ToString();
            Em.GetEvent<DebugMessage>().Publish($"{ItemName}运行了一次{MethodName} 耗时{Time}");
            State = ActionState.Completed;

            return true;
        }


        protected virtual void NextActionItemIndex(bool result)
        {
            //this.Flow.NextIndex++;
        }

        /// <summary>
        /// 运行方法
        /// </summary>
        /// <returns></returns>
        protected virtual bool RunMethod()
        {
            try
            {
                //var vars = GlobalVars.Ins.Vars[GlobalVars.FlowVars];



                #region 反射出方法

                dynamic method;
                if (IsConstructor)//构造器判断
                {
                    method = InitilizeConstructor();
                }
                else
                {
                    method = InitilizeMethod();
                }
                
                if (method == null) return false;

                #endregion 反射出方法

                #region 执行方法的对象

                Obj = null;

                if (!string.IsNullOrEmpty(ObjName))
                {
                    Obj = GlobalVars.Ins.GetVar(ObjGuid).Value;
                }

                #endregion 执行方法的对象

                #region 参数数组对象

                var objs = new List<object>();
                for (var index = 0; index < Parms.Count; index++)
                {
                    var item = Parms[index];
                    object temp = null;
                    if (!item.InputOrSelect)
                    {
                        //if (vars.ContainsKey(item.VarName)) temp = vars[item.VarName].Value;
                        temp = GlobalVars.Ins.GetVar(item.VarGuid).Value;
                    }
                    else
                    {
                        var valueType = Type.GetType(ParaTypes[index]);
                        if (valueType == typeof(int)) temp = Convert.ToInt32(item.Value);
                        else if (valueType == typeof(uint)) temp = Convert.ToUInt32(item.Value);
                        else if (valueType == typeof(short)) temp = Convert.ToInt16(item.Value);
                        else if (valueType == typeof(ushort)) temp = Convert.ToUInt16(item.Value);
                        else if (valueType == typeof(long)) temp = Convert.ToInt64(item.Value);
                        else if (valueType == typeof(ulong)) temp = Convert.ToUInt64(item.Value);
                        else if (valueType == typeof(Single)) temp = Convert.ToSingle(item.Value);
                        else if (valueType == typeof(double)) temp = Convert.ToDouble(item.Value);
                        else
                        {
                            temp = item.Value;
                        }
                    }
                    if (temp != null) objs.Add(temp);
                }

                #endregion 参数数组对象

                #region 执行

                object[] objArray = null;
                if (objs.Count > 0)
                {
                    objArray = objs.ToArray();
                }

                dynamic result;
                if (IsConstructor)//构造器判断
                {
                    result = method.Invoke(objArray);
                }
                else
                {
                    result = method.Invoke(Obj, objArray);
                }
                

                #endregion 执行

                #region 处理返回值

                if (!ReturnType.Contains("Void") && !string.IsNullOrEmpty(ReturnObjName))
                {
                    var varObj = GlobalVars.Ins.GetVar(ReturnObjGuid);
                    varObj.Value = result;
                }

                #endregion 处理返回值
            }
            catch (Exception e)
            {
                Em.GetEvent<DebugMessage>().Publish($"运行{ItemName}时出现异常:{e.Message}");
                return false;
            }

            return true;
        }

        /// <summary>
        /// 初始化方法
        /// </summary>
        /// <returns></returns>
        private MethodInfo InitilizeMethod()
        {
            string fileName = Environment.CurrentDirectory + "\\" + Dll;
            var curAssembly = Assembly.LoadFile(fileName);
            var tp = curAssembly.GetType(TypeName);                   
            var method = tp.GetMethod(MethodName, ParaTypes.Select(Type.GetType).ToArray());//传入参数列表才能获得重载方法           
            return method;
        }

        #region  初始化构造器

        private ConstructorInfo InitilizeConstructor()
        {
            string fileName = Environment.CurrentDirectory + "\\" + Dll;
            var curAssembly = Assembly.LoadFile(fileName);
            var tp = curAssembly.GetType(TypeName);
            var method = tp.GetConstructor(ParaTypes.Select(Type.GetType).ToArray());          
            return method;
        }

        #endregion

        #endregion 公有方法

        //---------------下面是流程图相关内容

        #region Fields

        /// <summary>
        /// 边界长度
        /// </summary>
        private int _borderLength = 20;
        /// <summary>
        /// 页边空白
        /// </summary>
        private int _marginBottom = 5;

        /// <summary>
        /// 固定底部连接器
        /// </summary>
        protected Connector cBottom, cLeft, cRight, cTop;

        /// <summary>
        /// 任何形状所在的矩形
        /// </summary>
        public Rectangle ToolRectangle { get; set; }

        /// <summary>
        /// 可以将连接连接到的连接器的集合
        /// </summary>
        protected List<Connector> connectors;

        /// <summary>
        /// 形状上的文本
        /// </summary>
        protected string text = string.Empty;

        //protected Image Icon = null;
        //public int Index = -1;

        /// <summary>
        /// 规模
        /// </summary>
        [Browsable(false)]
        public double Scale = 1;

        /// <summary>
        /// 显示边界
        /// </summary>
        private bool showBorder = true;

        /// <summary>
        /// 形状的背景色
        /// </summary>
        protected Color backGroundColor = Color.White;

        /// <summary>
        /// 边框颜色
        /// </summary>
        protected Color borderColor = Color.Black;

        /// <summary>
        /// 边框选择颜色
        /// </summary>
        protected Color borderSelectedColor = Color.GreenYellow;

        #endregion Fields

        #region Properties

        /// <summary>
        /// 获取或设置此形状的连接器
        /// </summary>
        [Browsable(false), JsonIgnore]
        public List<Connector> Connectors
        {
            get { return connectors; }
            set { connectors = value; }
        }

        /// <summary>
        /// 显示底部源点
        /// </summary>
        [Browsable(true), Description("显示底部源点"), Category("Layout")]
        public bool EnableBottomSourceConnector { get; set; } = true;

        /// <summary>
        /// 显示左侧源点
        /// </summary>
        [Browsable(true), Description("显示左侧源点"), Category("Layout")]
        public bool EnableLeftSourceConnector { get; set; } = false;

        /// <summary>
        /// 显示右侧源点
        /// </summary>
        [Browsable(true), Description("显示右侧源点"), Category("Layout")]
        public bool EnableRightSourceConnector { get; set; } = false;

        /// <summary>
        /// 显示顶部源点
        /// </summary>
        [Browsable(true), Description("显示顶部源点"), Category("Layout")]
        public bool EnableTopSourceConnector { get; set; } = true;

        /// <summary>
        /// 显示底部目标点
        /// </summary>
        [Browsable(true), Description("显示底部目标点"), Category("Layout")]
        public bool EnableBottomTargetConnector { get; set; } = false;

        /// <summary>
        /// 显示左侧目标点
        /// </summary>
        [Browsable(true), Description("显示左侧目标点"), Category("Layout")]
        public bool EnableLeftTargetConnector { get; set; } = false;

        /// <summary>
        /// 显示右侧目标点
        /// </summary>
        [Browsable(true), Description("显示右侧目标点"), Category("Layout")]
        public bool EnableRightTargetConnector { get; set; } = false;

        /// <summary>
        /// 显示顶部目标点
        /// </summary>
        [Browsable(true), Description("显示顶部目标点"), Category("Layout")]
        public bool EnableTopTargetConnector { get; set; } = false;

        /// <summary>
        /// 形状名称
        /// </summary>
        [Browsable(false)]
        public virtual string ShapeName => "ShapeBase";

        /// <summary>
        /// 工具箱规模
        /// </summary>
        [Browsable(false)]
        public virtual double ToolBoxScale => 1;

        /// <summary>
		/// 获取或设置形状的宽度
		/// </summary>
		[Browsable(true), Description("宽度"), Category("Layout")]
        public int Width
        {
            get { return (int)(this.ToolRectangle.Width * Scale); }
            set { Resize(value, this.Height); }
        }

        /// <summary>
        /// 获取或设置形状的高度
        /// </summary>
        [Browsable(true), Description("高度"), Category("Layout")]
        public int Height
        {
            get { return (int)(this.ToolRectangle.Height * Scale); }
            set { Resize(this.Width, value); }
        }

        /// <summary>
        /// 获取或设置形状的文本
        /// </summary>
        [Browsable(true), Description("显示的文本"), Category("Layout")]
        public string Text
        {
            get { return this.text; }
            set { this.text = value; this.Invalidate(); }
        }

        /// <summary>
        /// 左上角的x坐标
        /// </summary>
        [Browsable(true), Description("X坐标"), Category("Layout")]
        public int X
        {
            get { return ToolRectangle.X; }
            set
            {

                Point p = new Point(value - ToolRectangle.X, 0);

                if (Site != null)
                {
                    this.Move(p);
                    Site.Invalidate(); //note that 'this.Invalidate()' will not be enough
                }

            }
        }

        /// <summary>
        /// 左上角的y坐标
        /// </summary>
        [Browsable(true), Description("Y坐标"), Category("Layout")]
        public int Y
        {
            get { return ToolRectangle.Y; }
            set
            {
                Point p = new Point(0, value - ToolRectangle.Y);
                if (Site != null)
                {
                    this.Move(p);
                    Site.Invalidate();
                }

            }
        }

        /// <summary>
        /// 是否显示边框
        /// </summary>
        [Browsable(true), Description("是否显示边框"), Category("Layout")]
        public bool ShowBorder
        {
            get { return showBorder; }
            set { showBorder = value; Invalidate(); }
        }

        /// <summary>
		/// 形状的背景色
		/// </summary>
		[Browsable(true), Description("背景颜色"), Category("Layout")]
        public Color BackGroundColor
        {
            get { return backGroundColor; }
            set { backGroundColor = value; Invalidate(); }
        }

        /// <summary>
        /// 边框颜色
        /// </summary>
        [Browsable(true), Description("边框颜色"), Category("Layout")]
        public Color BoderColor
        {
            get { return borderColor; }
            set { borderColor = value; Invalidate(); }
        }

        /// <summary>
        /// 边框选中后颜色
        /// </summary>
        [Browsable(true), Description("边框选中后颜色"), Category("Layout")]
        public Color BoderSelectedColor
        {
            get { return borderSelectedColor; }
            set { borderSelectedColor = value; Invalidate(); }
        }

        /// <summary>
        /// 获取或设置工具的位置
        /// </summary>
        [Browsable(false)]
        public Point Location
        {
            get { return new Point(this.ToolRectangle.X, this.ToolRectangle.Y); }
            set
            {
                //we use the move method but it requires the delta value, not an absolute position!
                Point p = new Point(value.X - ToolRectangle.X, value.Y - ToolRectangle.Y);
                //if you'd use this it would indeed move the shape but not the connector s of the shape
                //this.rectangle.X = value.X; this.rectangle.Y = value.Y; Invalidate();
                this.Move(p);
            }
        }

        /// <summary>
        /// 状态机状态
        /// </summary>
        private ActionState _state;

        /// <summary>
        /// 圆角率
        /// </summary>
        [Browsable(true), Description("圆角率"), Category("Layout")]
        public int CornerRadius
        {
            get
            {
                return _cornerRadius;
            }
            set
            {
                _cornerRadius = value;
            }
        }
        private int _cornerRadius = 10;

        #endregion Properties


        #region Methods

        /// <summary>
        /// 总结构造函数使用的初始化
        /// </summary>
        public void InitCanvas(Canvas site)
        {
            this.site = site;


        }

        /// <summary>
        /// 被画布调用，连接点被击中
        /// </summary>
        /// <param name="p">the mouse coordinates</param>
        /// <param name="targetNode">是否为目标节点</param>
        /// <returns>the connector hit by the mouse</returns>
        public virtual Connector HitConnector(Point p, bool targetNode = false)
        {
            Point point0 = new Point(0, 0);
            if (this.site != null) point0 = this.site.ViewOriginPoint.GetPoint();
            Rectangle rect = new Rectangle(p, new Size(5, 5));

            #region 上

            var contentionRectangle = new Rectangle(
                (ToolRectangle.Width - _borderLength) / 2 + ToolRectangle.X + point0.X,
                (int)((ToolRectangle.Y + point0.Y - _marginBottom) - _borderLength * Math.Sin(Math.PI / 3)),
                _borderLength, _borderLength);

            if (contentionRectangle.Contains(rect))
            {
                if (!EnableTopSourceConnector)
                {
                    return null;
                }

                Point point = cTop.Point.GetPoint();
                point.Offset(point0.X - 7, point0.Y - 7);
                //return base.HitConnector(point);
                return cTop;
            }

            #endregion 上

            #region 下

            contentionRectangle = new Rectangle(
                (ToolRectangle.Width - _borderLength) / 2 + ToolRectangle.X + point0.X,
                ToolRectangle.Y + point0.Y + ToolRectangle.Height + _marginBottom,
                _borderLength, _borderLength);

            if (contentionRectangle.Contains(rect))
            {
                if (!EnableBottomSourceConnector)
                {
                    return null;
                }

                Point point = cBottom.Point.GetPoint();
                point.Offset(point0.X - 7, point0.Y - 7);
                //return base.HitConnector(point);
                return cBottom;
            }

            #endregion 下

            #region 右

            contentionRectangle = new Rectangle(
                ToolRectangle.Width + ToolRectangle.X + point0.X + _marginBottom,
                (ToolRectangle.Height - _borderLength) / 2 + ToolRectangle.Y + point0.Y,
                _borderLength, _borderLength);

            if (contentionRectangle.Contains(rect))
            {
                if (!EnableRightSourceConnector)
                {
                    return null;
                }

                Point point = cRight.Point.GetPoint();
                point.Offset(point0.X - 7, point0.Y - 7);
                //return base.HitConnector(point);
                return cRight;
            }

            #endregion 右

            #region 左

            contentionRectangle = new Rectangle(
                ToolRectangle.X + point0.X - _marginBottom - _borderLength,
                (ToolRectangle.Height - _borderLength) / 2 + ToolRectangle.Y + point0.Y,
                _borderLength, _borderLength);

            if (contentionRectangle.Contains(rect))
            {
                if (!EnableLeftSourceConnector)
                {
                    return null;
                }

                Point point = cLeft.Point.GetPoint();
                point.Offset(point0.X - 7, point0.Y - 7);
                //return base.HitConnector(point);
                return cLeft;
            }

            #endregion 左

            for (int k = 0; k < connectors.Count; k++)
            {
                if (connectors[k].Hit(p))
                {
                    if (!targetNode)
                    {
                        if (!EnableBottomSourceConnector && connectors[k].ConnectorDirection == ConnectorDirection.Down)
                        {
                            return null;
                        }

                        if (!EnableTopSourceConnector && connectors[k].ConnectorDirection == ConnectorDirection.Up)
                        {
                            return null;
                        }

                        if (!EnableRightSourceConnector && connectors[k].ConnectorDirection == ConnectorDirection.Right)
                        {
                            return null;
                        }

                        if (!EnableLeftSourceConnector && connectors[k].ConnectorDirection == ConnectorDirection.Left)
                        {
                            return null;
                        }
                    }
                    else
                    {
                        if (!EnableBottomTargetConnector && connectors[k].ConnectorDirection == ConnectorDirection.Down)
                        {
                            return null;
                        }

                        if (!EnableTopTargetConnector && connectors[k].ConnectorDirection == ConnectorDirection.Up)
                        {
                            return null;
                        }

                        if (!EnableRightTargetConnector && connectors[k].ConnectorDirection == ConnectorDirection.Right)
                        {
                            return null;
                        }

                        if (!EnableLeftTargetConnector && connectors[k].ConnectorDirection == ConnectorDirection.Left)
                        {
                            return null;
                        }
                    }

                    connectors[k].Hovered = true;
                    connectors[k].Invalidate();
                    return connectors[k];
                }
                else
                {
                    connectors[k].Hovered = false;
                    connectors[k].Invalidate();
                }
            }
            return null;
        }

        /// <summary>
        /// 调整形状大小并移动连接件
        /// </summary>
        /// <param name="width"></param>
        /// <param name="height"></param>
        public virtual void Resize(int width, int height)
        {
            //this.Rectangle1.Height = height;
            //this.Rectangle1.Width = width;

            if (cBottom != null)
                cBottom.Point = new Point(ToolRectangle.Left + ToolRectangle.Width / 2, ToolRectangle.Bottom);
            if (cLeft != null)
                cLeft.Point = new Point(ToolRectangle.Left, ToolRectangle.Top + ToolRectangle.Height / 2);
            if (cRight != null)
                cRight.Point = new Point(ToolRectangle.Right, ToolRectangle.Top + ToolRectangle.Height / 2);
            if (cTop != null)
                cTop.Point = new Point(ToolRectangle.Left + ToolRectangle.Width / 2, ToolRectangle.Top);
            Invalidate();
        }

        /// <summary>
        /// 位置变更
        /// </summary>
        protected override void SiteChanged()
        {
            connectors.Remove(cBottom);
            cBottom = new Connector(new Point(ToolRectangle.Left + ToolRectangle.Width / 2, ToolRectangle.Bottom))
            {
                OwnerEntity = this,
                ConnectorsIndexOfContainEntity = connectors.Count,
                Site = this.site,
                OwnerID = this.ObjectId,
                Index = connectors.Count,
                Name = "Bottom connector",
                ConnectorDirection = ConnectorDirection.Down
            };
            connectors.Add(cBottom);

            connectors.Remove(cLeft);
            cLeft = new Connector(new Point(ToolRectangle.Left, ToolRectangle.Top + ToolRectangle.Height / 2))
            {
                OwnerEntity = this,
                ConnectorsIndexOfContainEntity = connectors.Count,
                Site = this.site,
                OwnerID = this.ObjectId,
                Index = connectors.Count,
                Name = "Left connector",
                ConnectorDirection = ConnectorDirection.Left
            };
            connectors.Add(cLeft);

            connectors.Remove(cRight);
            cRight = new Connector(new Point(ToolRectangle.Right, ToolRectangle.Top + ToolRectangle.Height / 2))
            {
                OwnerEntity = this,
                ConnectorsIndexOfContainEntity = connectors.Count,
                Site = this.site,
                OwnerID = this.ObjectId,
                Index = connectors.Count,
                Name = "Right connector",
                ConnectorDirection = ConnectorDirection.Right
            };
            connectors.Add(cRight);

            connectors.Remove(cTop);
            cTop = new Connector(new Point(ToolRectangle.Left + ToolRectangle.Width / 2, ToolRectangle.Top))
            {
                OwnerEntity = this,
                ConnectorsIndexOfContainEntity = connectors.Count,
                Site = this.site,
                OwnerID = this.ObjectId,
                Index = connectors.Count,
                Name = "Top connector",
                ConnectorDirection = ConnectorDirection.Up
            };
            connectors.Add(cTop);
        }

        /// <summary>
        /// 覆盖抽象绘制方法
        /// </summary>
        /// <param name="g"></param>
        public override void Paint(Graphics g)
        {
            g.SmoothingMode = SmoothingMode.AntiAlias;
            Point point = new Point(0, 0);
            if (this.site != null)
                point = this.site.ViewOriginPoint.GetPoint();

            Brush brush = new SolidBrush(BackGroundColor);
            Rectangle rect = new Rectangle(ToolRectangle.X + point.X, ToolRectangle.Y + point.Y, this.Width, this.Height);
            using (GraphicsPath graphicsPath = CreatePath(rect, (int)(_cornerRadius * Scale)))
            {
                g.FillPath(brush, graphicsPath);
                if (Hovered || isSelected)
                {
                    Pen p = new Pen(BoderSelectedColor, 2F);
                    p.StartCap = LineCap.Round;
                    p.EndCap = LineCap.Round;
                    p.LineJoin = LineJoin.Round;
                    g.DrawPath(p, graphicsPath);
                }
                else if (ShowBorder)
                {
                    Pen p = new Pen(BoderColor);
                    p.StartCap = LineCap.Round;
                    p.EndCap = LineCap.Round;
                    p.LineJoin = LineJoin.Round;
                    g.DrawPath(p, graphicsPath);
                }
            }
            if (this.site != null)
                point = this.site.ViewOriginPoint.GetPoint();

            if (isSelected)
            {
                Point point1, point2, point3;
                Point[] pntArr;

                if (EnableTopSourceConnector)
                {
                    #region 上连接点

                    point1 = new Point(
                        (ToolRectangle.Width - _borderLength) / 2 + ToolRectangle.X + point.X,
                        ToolRectangle.Y + point.Y - _marginBottom);

                    point2 = new Point(
                        (ToolRectangle.Width + _borderLength) / 2 + ToolRectangle.X + point.X,
                        ToolRectangle.Y + point.Y - _marginBottom);

                    point3 = new Point(
                        ToolRectangle.Width / 2 + ToolRectangle.X + point.X,
                        (int)((ToolRectangle.Y + point.Y - _marginBottom) - _borderLength * Math.Sin(Math.PI / 3)));

                    pntArr = new[] { point1, point2, point3 };
                    g.FillPolygon(Brushes.Gold, pntArr);

                    #endregion 上连接点
                }

                if (EnableBottomSourceConnector)
                {
                    #region 下连接点

                    point1 = new Point(
                        (ToolRectangle.Width - _borderLength) / 2 + ToolRectangle.X + point.X,
                        ToolRectangle.Y + point.Y + ToolRectangle.Height + _marginBottom);

                    point2 = new Point(
                        (ToolRectangle.Width + _borderLength) / 2 + ToolRectangle.X + point.X,
                        ToolRectangle.Y + point.Y + ToolRectangle.Height + _marginBottom);

                    point3 = new Point(
                        ToolRectangle.Width / 2 + ToolRectangle.X + point.X,
                        (int)((ToolRectangle.Y + point.Y + ToolRectangle.Height + _marginBottom) + _borderLength * Math.Sin(Math.PI / 3)));

                    pntArr = new[] { point1, point2, point3 };
                    g.FillPolygon(Brushes.Gold, pntArr);

                    #endregion 下连接点
                }

                if (EnableRightSourceConnector)
                {
                    #region 右连接点

                    point1 = new Point(
                        ToolRectangle.Width + ToolRectangle.X + point.X + _marginBottom,
                        (ToolRectangle.Height - _borderLength) / 2 + ToolRectangle.Y + point.Y);

                    point2 = new Point(
                        ToolRectangle.Width + ToolRectangle.X + point.X + _marginBottom,
                        (ToolRectangle.Height + _borderLength) / 2 + ToolRectangle.Y + point.Y);

                    point3 = new Point(
                        (int)(ToolRectangle.Width + ToolRectangle.X + point.X + _marginBottom + _borderLength * Math.Sin(Math.PI / 3)),
                        ToolRectangle.Height / 2 + ToolRectangle.Y + point.Y);

                    pntArr = new[] { point1, point2, point3 };
                    g.FillPolygon(Brushes.Gold, pntArr);

                    #endregion 右连接点
                }

                if (EnableLeftSourceConnector)
                {
                    #region 左连接点

                    point1 = new Point(
                        ToolRectangle.X + point.X - _marginBottom,
                        (ToolRectangle.Height - _borderLength) / 2 + ToolRectangle.Y + point.Y);

                    point2 = new Point(
                        ToolRectangle.X + point.X - _marginBottom,
                        (ToolRectangle.Height + _borderLength) / 2 + ToolRectangle.Y + point.Y);

                    point3 = new Point(
                        (int)(ToolRectangle.X + point.X - _marginBottom - _borderLength * Math.Sin(Math.PI / 3)),
                        ToolRectangle.Height / 2 + ToolRectangle.Y + point.Y);

                    pntArr = new[] { point1, point2, point3 };
                    g.FillPolygon(Brushes.Gold, pntArr);

                    #endregion 左连接点
                }
            }

            for (int k = 0; k < connectors.Count; k++)
            {
                connectors[k].Paint(g);
            }
            //绘制图标
            if (text != string.Empty)
            {
                StringFormat stringFormat = new StringFormat();
                stringFormat.LineAlignment = StringAlignment.Center;
                stringFormat.Alignment = StringAlignment.Center;
                Rectangle rectangle = new Rectangle(this.ToolRectangle.X + point.X, this.ToolRectangle.Y + point.Y, this.ToolRectangle.Width, this.ToolRectangle.Height);
                //if (BitIcon != null)
                //{
                //    g.DrawImage(BitIcon, this.ToolRectangle.X + point.X + 5, this.ToolRectangle.Y + point.Y, 32, 32);
                //    Rectangle rectangle1 = new Rectangle(this.ToolRectangle.X + point.X + 10, this.ToolRectangle.Y + point.Y, this.ToolRectangle.Width, this.ToolRectangle.Height);
                //    g.DrawString(text, Font, Brushes.Black, rectangle1, stringFormat);
                //}
                //else
                //{
                //    g.DrawString(text, Font, Brushes.Black, rectangle, stringFormat);
                //}
                g.DrawString(text, Font, Brushes.Black, rectangle, stringFormat);
            }
        }

        /// <summary>
        /// 重写抽象命中方法
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public override bool Hit(System.Drawing.Point p)
        {
            if (this.site == null) return false;
            Point point = new Point(0, 0);
            if (this.site != null)
                point = this.site.ViewOriginPoint.GetPoint();

            p.X = p.X - point.X;
            p.Y = p.Y - point.Y;

            Rectangle r = new Rectangle(p, new Size(5, 5));
            return ToolRectangle.Contains(r);
        }

        /// <summary>
        /// 覆盖抽象的 无效 方法
        /// </summary>
        public override void Invalidate()
        {
            if (this.site == null) return;
            Point point = this.site.ViewOriginPoint.GetPoint();
            Rectangle r = ToolRectangle;
            r.X += point.X;
            r.Y += point.Y;
            r.Offset(-5, -5);
            r.Inflate(20, 20);
            site.Invalidate(r);
        }

        /// <summary>
        ///使用给定的移位移动工具
        /// </summary>
        /// <param name="p">r点位</param>
        public override void Move(Point p)
        {
            if (this.site == null) return;
            ToolRectangle = new Rectangle(ToolRectangle.X + p.X, ToolRectangle.Y + p.Y, ToolRectangle.Width, ToolRectangle.Height);
            //this.ToolRectangle.X += p.X;
            //this.ToolRectangle.Y += p.Y;
            for (int k = 0; k < this.connectors.Count; k++)
            {
                connectors[k].Move(p);
            }
            this.Invalidate();
        }
        /// <summary>
        /// 创建路径
        /// </summary>
        /// <param name="rect"></param>
        /// <param name="cornerRadius"></param>
        /// <returns></returns>
        protected virtual GraphicsPath CreatePath(Rectangle rect, int cornerRadius)
        {
            GraphicsPath roundedRect = new GraphicsPath();
            roundedRect.AddArc(rect.X, rect.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
            roundedRect.AddLine(rect.X + cornerRadius, rect.Y, rect.Right - cornerRadius * 2, rect.Y);
            roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
            roundedRect.AddLine(rect.Right, rect.Y + cornerRadius * 2, rect.Right, rect.Y + rect.Height - cornerRadius * 2);
            roundedRect.AddArc(rect.X + rect.Width - cornerRadius * 2, rect.Y + rect.Height - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
            roundedRect.AddLine(rect.Right - cornerRadius * 2, rect.Bottom, rect.X + cornerRadius * 2, rect.Bottom);
            roundedRect.AddArc(rect.X, rect.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
            roundedRect.AddLine(rect.X, rect.Bottom - cornerRadius * 2, rect.X, rect.Y + cornerRadius * 2);
            roundedRect.CloseFigure();
            return roundedRect;
        }

        #endregion Methods

        #region 状态机
        public enum ActionState
        {
            Idle,
            Ready,
            Running,
            Completed
        }

        public ActionState State
        {
            get => _state;
            set
            {
                _state = value;
                switch (_state)
                {
                    case ActionState.Idle:
                        BackGroundColor = Color.White;
                        break;
                    case ActionState.Ready:
                        break;
                    case ActionState.Running:
                        BackGroundColor = Color.Yellow;
                        break;
                    case ActionState.Completed:
                        BackGroundColor = Color.Aquamarine;
                        break;
                    default:
                        BackGroundColor = Color.White;
                        break;
                }
            }
        }

        #endregion
    }


    /// <summary>
    /// 末端节点
    /// </summary>
    public class EndNode : ActionItem
    {
        /// <summary>
        /// 运行方法
        /// </summary>
        /// <returns></returns>
        protected override bool RunMethod()
        {
            Em.GetEvent<DebugMessage>().Publish("流程运行完成！");
            return true;
        }
    }
    /// <summary>
    /// 方法参数类，用于记录反射出方法的参数信息
    /// </summary>
    public class MethodParms : BindableBase
    {
        
        private bool _inputOrSelect = true;
        /// <summary>
        /// 开启后用于选择全局参数或者手动输入参数来给予参数值
        /// </summary>
        public bool InputOrSelect
        {
            get { return _inputOrSelect; }
            set { SetProperty(ref _inputOrSelect, value); }
        }
        
        private string _varName;
        /// <summary>
        /// 通过全局变量名称给反射出方法的参数赋值
        /// </summary>
        public string VarName
        {
            get { return _varName; }
            set { SetProperty(ref _varName, value); }
        }
        
        private object _value;
        /// <summary>
        /// 全局变量名称对应的值
        /// </summary>
        public object Value
        {
            get { return _value; }
            set { SetProperty(ref _value, value); }
        }
        
        private string _varGuid;
        /// <summary>
        /// 参数随机标志符
        /// </summary>
        public string VarGuid
        {
            get { return _varGuid; }
            set { SetProperty(ref _varGuid, value); }
        }
        
        private string _name;
        /// <summary>
        /// 用于记录反射出方法的参数名称
        /// </summary>
        public string Name
        {
            get { return _name; }
            set { SetProperty(ref _name, value); }
        }
        
        private string _type;
        /// <summary>
        /// 用于记录反射出方法的参数类型
        /// </summary>
        public string Type
        {
            get { return _type; }
            set { SetProperty(ref _type, value); }
        }
                     
    }
    /// <summary>
    /// 代理类
    /// </summary>
    public class Proxy
    {
       

        #region Constructor

        /// <summary>
        /// 构造函数，传入画布控件
        /// </summary>
        /// <param name="site"></param>
        public Proxy(Canvas site)
        { this.site = site; }

        #endregion

        #region Fields && Properties

        /// <summary>
        /// 画布控件
        /// </summary>
        [Browsable(false)]
        public Canvas Site
        {
            get { return site; }
            set { site = value; }
        }
        private Canvas site;

        /// <summary>
        /// 背景颜色
        /// </summary>
        [Browsable(true), Description("背景颜色"), Category("Layout")]
        public Color BackColor
        {
            get { return this.site.BackColor; }
            set { this.site.BackColor = value; }
        }

        /// <summary>
        /// 获取/设置网格显示状态
        /// </summary>
        [Browsable(true), Description("获取/设置网格显示状态"), Category("Layout")]
        public bool ShowGrid
        {
            get { return this.site.ShowGrid; }
            set { this.site.ShowGrid = value; }
        }

        /// <summary>
        /// 视觉原点，左上角坐标
        /// </summary>
        [Browsable(true), Description("视觉原点，左上角坐标"), Category("Layout")]
        public DiagramPoint ViewOriginPoint
        {
            get { return this.site.ViewOriginPoint; }
            set { this.site.ViewOriginPoint = value; }
        }

        /// <summary>
        /// 连线默认颜色
        /// </summary>
        [Browsable(true), Description("连线默认颜色"), Category("Layout")]
        public Color LineColor
        {
            get { return this.site.LineColor; }
            set { this.site.LineColor = value; }
        }

        /// <summary>
        /// 连线选中颜色
        /// </summary>
        [Browsable(true), Description("连线选中颜色"), Category("Layout")]
        public Color LineSelectedColor
        {
            get { return this.site.LineSelectedColor; }
            set { this.site.LineSelectedColor = value; }
        }

        /// <summary>
        /// 连线悬停颜色
        /// </summary>
        [Browsable(true), Description("连线悬停颜色"), Category("Layout")]
        public Color LineHoveredColor
        {
            get { return this.site.LineHoveredColor; }
            set { this.site.LineHoveredColor = value; }
        }

        #endregion
    }
    /// <summary>
    /// 图解点位置信息
    /// </summary>
    public class DiagramPoint : Component
    {
        /// <summary>
        /// 点
        /// </summary>
        private Point _point = new Point();
        /// <summary>
        /// X偏移量
        /// </summary>
        [Description("X偏移量"), Category("Layout")]
        public int X
        {
            get
            {
                return _point.X;
            }
            set
            {
                _point.X = value;
            }
        }
        /// <summary>
        /// Y偏移量
        /// </summary>
        [Description("Y偏移量"), Category("Layout")]
        public int Y
        {
            get
            {
                return _point.Y;
            }
            set
            {
                _point.Y = value;
            }
        }

        /// <summary>
        /// 连接方向
        /// </summary>
        public ConnectorDirection ConnectorDirection = ConnectorDirection.Up;

        public DiagramPoint()
        {

        }

        /// <summary>
        /// 构造参数，传入X Y
        /// </summary>
        /// <param name="x"></param>
        /// <param name="y"></param>
        public DiagramPoint(int x, int y)
        {
            X = x;
            Y = y;
        }

        /// <summary>
        /// 获得偏移量
        /// </summary>
        /// <returns></returns>
        public Point GetPoint()
        {
            return _point;
        }

        public override string ToString()
        {
            return $"{X},{Y}";
        }

        public static implicit operator DiagramPoint(Point point)
        {
            return new DiagramPoint(point.X, point.Y);
        }
        /// <summary>
        /// 复制自己
        /// </summary>
        /// <returns></returns>
        public DiagramPoint Copy()
        {
            DiagramPoint diagramPoint = new DiagramPoint(this.X, this.Y);
            diagramPoint.ConnectorDirection = this.ConnectorDirection;
            return diagramPoint;
        }
    }

    public class Json
    {
        public static T Load<T>(string fileName)
        {
            try
            {
                object obj = null;
                if (File.Exists(fileName))
                {
                    string str = File.ReadAllText(fileName);
                    obj = JsonConvert.DeserializeObject<T>(str, new JsonSerializerSettings
                    {
                        NullValueHandling = NullValueHandling.Ignore,
                    });
                }
                return (T)obj;
            }
            catch (Exception ex)
            {
                UIMessageBox.ShowError($"加载Json时发现错误的工具,返回一个Null对象\r{ex.Message}\r{ex.StackTrace}");
                return default(T);
            }
        }

        public static T LoadExt<T>(string fileName)
        {
            try
            {
                object obj = null;
                if (File.Exists(fileName))
                {
                    string str = File.ReadAllText(fileName);
                    obj = JsonConvert.DeserializeObject<T>(str, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });
                }
                return (T)obj;
            }
            catch (Exception ex)
            {
                UIMessageBox.ShowError($"加载Json时发现错误的工具,返回一个Null对象\r{ex.Message}\r{ex.StackTrace}");
                return default(T);
            }
        }

        //-----------------------------------------------------------------------------------------------------
        /// <summary>
        /// 保存配置
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static bool Save<T>(string fileName, object obj)
        {
            string str = JsonConvert.SerializeObject(obj);
            File.WriteAllText(fileName, str);
            return true;
        }

        //-----------------------------------------------------------------------------------------------------
        /// <summary>
        /// 保存配置
        /// </summary>
        /// <param name="fileName"></param>
        /// <returns></returns>
        public static bool SaveExt<T>(string fileName, object obj)
        {
            string str = JsonConvert.SerializeObject(obj, new JsonSerializerSettings() { TypeNameHandling = TypeNameHandling.All });
            File.WriteAllText(fileName, str);
            return true;
        }

    }

    public class ParaPage : Attribute
    {
        public ParaPage(Type type)
        {
            PageType = type;
        }

        public Type PageType { get; set; }

        public UIPage GetParaPage(ActionItem actionItem)
        {
            var page = (UIPage)Activator.CreateInstance(PageType, actionItem);
            return page;
        }
    }

    #region 按键钩子 实现快捷键执行特定功能

    //Declare wrapper managed POINT class.
    [StructLayout(LayoutKind.Sequential)]
    public class POINT
    {
        public int x;
        public int y;
    }
    //Declare wrapper managed MouseHookStruct class.
    [StructLayout(LayoutKind.Sequential)]
    public class MouseHookStruct
    {
        public POINT pt;
        public int hwnd;
        public int wHitTestCode;
        public int dwExtraInfo;
    }
    //Declare wrapper managed KeyboardHookStruct class.

    [StructLayout(LayoutKind.Sequential)]
    public class KeyboardHookStruct
    {
        public int vkCode; //Specifies a virtual-key code. The code must be a value in the range 1 to 254.
        public int scanCode; // Specifies a hardware scan code for the key.
        public int flags; // Specifies the extended-key flag, event-injected flag, context code, and transition-state flag.
        public int time; // Specifies the time stamp for this message.
        public int dwExtraInfo; // Specifies extra information associated with the message.
    }

    /// <summary>
    /// 全局钩子
    /// </summary>
    public class GlobalHook
    {
        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
        public delegate int GlobalHookProc(int nCode, Int32 wParam, IntPtr lParam);
        public GlobalHook()
        {
            //Start();
        }
        ~GlobalHook()
        {
            Stop();
        }
        public event MouseEventHandler OnMouseActivity;
        public event KeyEventHandler KeyDown;
        public event KeyPressEventHandler KeyPress;
        public event KeyEventHandler KeyUp;

        /// <summary>
        /// 定义鼠标钩子句柄.
        /// </summary>
        static int _hMouseHook = 0;
        /// <summary>
        /// 定义键盘钩子句柄
        /// </summary>
        static int _hKeyboardHook = 0;

        public int HMouseHook
        {
            get { return _hMouseHook; }
        }
        public int HKeyboardHook
        {
            get { return _hKeyboardHook; }
        }

        /// <summary>
        /// 鼠标钩子常量(from Microsoft SDK  Winuser.h )
        /// </summary>
        public const int WH_MOUSE_LL = 14;
        /// <summary>
        /// 键盘钩子常量(from Microsoft SDK  Winuser.h )
        /// </summary>
        public const int WH_KEYBOARD_LL = 13;

        /// <summary>
        /// 定义鼠标处理过程的委托对象
        /// </summary>
        GlobalHookProc MouseHookProcedure;
        /// <summary>
        /// 键盘处理过程的委托对象
        /// </summary>
        GlobalHookProc KeyboardHookProcedure;

        //导入window 钩子扩展方法导入

        /// <summary>
        /// 安装钩子方法
        /// </summary>
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int SetWindowsHookEx(int idHook, GlobalHookProc lpfn, IntPtr hInstance, int threadId);

        /// <summary>
        /// 卸载钩子方法
        /// </summary>
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);

        //Import for CallNextHookEx.
        /// <summary>
        /// 使用这个函数钩信息传递给链中的下一个钩子过程。
        /// </summary>
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern int CallNextHookEx(int idHook, int nCode, Int32 wParam, IntPtr lParam);

        public bool Start()
        {
            // install Mouse hook
            //if (_hMouseHook == 0)
            //{
            //    // Create an instance of HookProc.
            //    MouseHookProcedure = new GlobalHookProc(MouseHookProc);
            //    try
            //    {
            //        _hMouseHook = SetWindowsHookEx(WH_MOUSE_LL,
            //            MouseHookProcedure,
            //            Marshal.GetHINSTANCE(
            //            //Assembly.GetExecutingAssembly().GetModules()[0]
            //            Assembly.GetEntryAssembly().GetModules()[0]),
            //            0);
            //    }
            //    catch (Exception err)
            //    { }
            //    //如果安装鼠标钩子失败
            //    if (_hMouseHook == 0)
            //    {
            //        Stop();
            //        return false;
            //        //throw new Exception("SetWindowsHookEx failed.");
            //    }
            //}
            //安装键盘钩子
            if (_hKeyboardHook == 0)
            {
                KeyboardHookProcedure = new GlobalHookProc(KeyboardHookProc);
                try
                {
                    _hKeyboardHook = SetWindowsHookEx(WH_KEYBOARD_LL,
                        KeyboardHookProcedure,
                        Marshal.GetHINSTANCE(
                        //Assembly.GetExecutingAssembly().GetModules()[0]
                        Assembly.GetEntryAssembly().GetModules()[0]),
                        0);
                }
                catch (Exception err2)
                { }
                //如果安装键盘钩子失败
                if (_hKeyboardHook == 0)
                {
                    Stop();
                    return false;
                    //throw new Exception("SetWindowsHookEx ist failed.");
                }
            }
            return true;
        }

        public void Stop()
        {
            bool retMouse = true;
            bool retKeyboard = true;
            if (_hMouseHook != 0)
            {
                retMouse = UnhookWindowsHookEx(_hMouseHook);
                _hMouseHook = 0;
            }
            if (_hKeyboardHook != 0)
            {
                retKeyboard = UnhookWindowsHookEx(_hKeyboardHook);
                _hKeyboardHook = 0;
            }
            //If UnhookWindowsHookEx fails.
            if (!(retMouse && retKeyboard))
            {
                //throw new Exception("UnhookWindowsHookEx ist failed.");
            }

        }
        /// <summary>
        /// 卸载hook,如果进程强制结束,记录上次钩子id,并把根据钩子id来卸载它
        /// </summary>
        public void Stop(int hMouseHook, int hKeyboardHook)
        {
            if (hMouseHook != 0)
            {
                UnhookWindowsHookEx(hMouseHook);
            }
            if (hKeyboardHook != 0)
            {
                UnhookWindowsHookEx(hKeyboardHook);
            }
        }

        private const int WM_MOUSEMOVE = 0x200;

        private const int WM_LBUTTONDOWN = 0x201;

        private const int WM_RBUTTONDOWN = 0x204;

        private const int WM_MBUTTONDOWN = 0x207;

        private const int WM_LBUTTONUP = 0x202;

        private const int WM_RBUTTONUP = 0x205;

        private const int WM_MBUTTONUP = 0x208;

        private const int WM_LBUTTONDBLCLK = 0x203;

        private const int WM_RBUTTONDBLCLK = 0x206;

        private const int WM_MBUTTONDBLCLK = 0x209;

        private int MouseHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            if ((nCode >= 0) && (OnMouseActivity != null))
            {
                MouseButtons button = MouseButtons.None;
                switch (wParam)
                {
                    case WM_LBUTTONDOWN:    //左键按下
                                            //case WM_LBUTTONUP:    //右键按下
                                            //case WM_LBUTTONDBLCLK:   //同时按下
                        button = MouseButtons.Left;
                        break;
                    case WM_RBUTTONDOWN:
                        //case WM_RBUTTONUP:
                        //case WM_RBUTTONDBLCLK:
                        button = MouseButtons.Right;
                        break;
                }
                int clickCount = 0;
                if (button != MouseButtons.None)
                    if (wParam == WM_LBUTTONDBLCLK || wParam == WM_RBUTTONDBLCLK)
                        clickCount = 2;
                    else clickCount = 1;

                //Marshall the data from callback.
                MouseHookStruct MyMouseHookStruct =
                    (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));
                MouseEventArgs e = new MouseEventArgs(
                    button,
                    clickCount,
                    MyMouseHookStruct.pt.x,
                    MyMouseHookStruct.pt.y,
                    0);
                OnMouseActivity(this, e);
            }
            return CallNextHookEx(_hMouseHook, nCode, wParam, lParam);
        }

        //The ToAscii function translates the specified virtual-key code and keyboard state to the corresponding character or characters. The function translates the code using the input language and physical keyboard layout identified by the keyboard layout handle.

        [DllImport("user32")]
        public static extern int ToAscii(int uVirtKey, //[in] Specifies the virtual-key code to be translated.
            int uScanCode, // [in] Specifies the hardware scan code of the key to be translated. The high-order bit of this value is set if the key is up (not pressed).
            byte[] lpbKeyState, // [in] Pointer to a 256-byte array that contains the current keyboard state. Each element (byte) in the array contains the state of one key. If the high-order bit of a byte is set, the key is down (pressed). The low bit, if set, indicates that the key is toggled on. In this function, only the toggle bit of the CAPS LOCK key is relevant. The toggle state of the NUM LOCK and SCROLL LOCK keys is ignored.
            byte[] lpwTransKey, // [out] Pointer to the buffer that receives the translated character or characters.
            int fuState); // [in] Specifies whether a menu is active. This parameter must be 1 if a menu is active, or 0 otherwise.
                          //The GetKeyboardState function copies the status of the 256 virtual keys to the specified buffer.
        [DllImport("user32")]
        public static extern int GetKeyboardState(byte[] pbKeyState);

        private const int WM_KEYDOWN = 0x100;
        private const int WM_KEYUP = 0x101;
        private const int WM_SYSKEYDOWN = 0x104;
        private const int WM_SYSKEYUP = 0x105;

        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
        {
            // it was ok and someone listens to events
            if ((nCode >= 0) && (KeyDown != null || KeyUp != null || KeyPress != null))
            {
                KeyboardHookStruct MyKeyboardHookStruct =
                    (KeyboardHookStruct)Marshal.PtrToStructure(lParam,
                    typeof(KeyboardHookStruct));
                // raise KeyDown
                if (KeyDown != null && (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN))
                {
                    Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e = new KeyEventArgs(keyData);
                    KeyDown(this, e);
                }
                // raise KeyPress
                if (KeyPress != null && wParam == WM_KEYDOWN)
                {
                    byte[] keyState = new byte[256];
                    GetKeyboardState(keyState);
                    byte[] inBuffer = new byte[2];
                    if (ToAscii(MyKeyboardHookStruct.vkCode,
                        MyKeyboardHookStruct.scanCode,
                        keyState,
                        inBuffer,
                        MyKeyboardHookStruct.flags) == 1)
                    {
                        KeyPressEventArgs e = new KeyPressEventArgs((char)inBuffer[0]);
                        KeyPress(this, e);
                    }
                }
                // raise KeyUp
                if (KeyUp != null && (wParam == WM_KEYUP || wParam == WM_SYSKEYUP))
                {
                    Keys keyData = (Keys)MyKeyboardHookStruct.vkCode;
                    KeyEventArgs e = new KeyEventArgs(keyData);
                    KeyUp(this, e);
                }
            }
            return CallNextHookEx(_hKeyboardHook, nCode, wParam, lParam);
        }
    }
    #endregion

    public class DeletingEventArgs : EventArgs
    {
        public bool Cancel { get; set; } = false;
    }
    public class SelectElementChangedEventArgs : EventArgs
    {
        /// <summary>
        /// 当前实体
        /// </summary>
        public Entity CurrentEntity { get; set; }
        /// <summary>
        /// 先前实体
        /// </summary>
        public Entity PreviousEntity { get; set; }
    }

    #region 事件聚合器相关

    public class SelectActionChanged : PubSubEvent<ActionItem> { }
    public class DebugMessage : PubSubEvent<string> { }

    #endregion

    #endregion
}
